Skip to content

Commit

Permalink
ALL: Add typeof call
Browse files Browse the repository at this point in the history
  • Loading branch information
MineGame159 committed Jan 24, 2024
1 parent e774f43 commit 6754eef
Show file tree
Hide file tree
Showing 15 changed files with 229 additions and 6 deletions.
3 changes: 2 additions & 1 deletion cmd/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func Build(project *workspace.Project, entrypoint *ir.Module, optimizationLevel
_ = os.Mkdir("build", 0750)

// Emit project IR
ctx := codegen.Context{}
irPaths := make([]string, 0, len(project.Files))

for _, file := range project.Files {
Expand All @@ -26,7 +27,7 @@ func Build(project *workspace.Project, entrypoint *ir.Module, optimizationLevel
return "", err
}

module := codegen.Emit(file.AbsolutePath(), project.GetResolverFile(file.Ast), file.Ast)
module := codegen.Emit(&ctx, file.AbsolutePath(), project.GetResolverFile(file.Ast), file.Ast)
llvm.WriteText(module, irFile)

_ = irFile.Close()
Expand Down
1 change: 1 addition & 0 deletions cmd/lsp/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ func getGlobalCompletions(resolver ast.Resolver, c *completions, symbolsOnlyType

c.add(protocol.CompletionItemKindFunction, "sizeof", "(<type>) u32")
c.add(protocol.CompletionItemKindFunction, "alignof", "(<type>) u32")
c.add(protocol.CompletionItemKindFunction, "typeof", "(<expression>) u32")
}

// Language defined types and functions
Expand Down
8 changes: 8 additions & 0 deletions cmd/lsp/highlighter.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ func (h *highlighter) VisitTypeCall(expr *ast.TypeCall) {
expr.AcceptChildren(h)
}

func (h *highlighter) VisitTypeof(expr *ast.Typeof) {
h.add(expr.Callee, functionKind)

expr.AcceptChildren(h)
}

func (h *highlighter) VisitCall(expr *ast.Call) {
expr.AcceptChildren(h)
}
Expand All @@ -218,6 +224,8 @@ func (h *highlighter) visitExprResult(node ast.Node, result *ast.ExprResult) {
switch result.Kind {
case ast.TypeResultKind:
switch result.Type.(type) {
case *ast.Primitive:
h.add(node, typeKind)
case *ast.Struct:
h.add(node, classKind)
case *ast.Enum:
Expand Down
31 changes: 28 additions & 3 deletions core/ast/cst2ast/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ func (c *converter) convertExpr(node cst.Node) ast.Expr {
return c.convertCallExpr(node)
case cst.TypeCallExprNode:
return c.convertTypeCallExpr(node)
case cst.TypeofExprNode:
return c.convertTypeofExpr(node)
case cst.StructExprNode:
return c.convertStructExpr(node)
case cst.ArrayExprNode:
Expand Down Expand Up @@ -203,18 +205,41 @@ func (c *converter) convertCallExpr(node cst.Node) ast.Expr {
}

func (c *converter) convertTypeCallExpr(node cst.Node) ast.Expr {
var name *ast.Token
var callee *ast.Token
var arg ast.Type

for _, child := range node.Children {
if child.Kind == cst.IdentifierNode {
name = c.convertToken(child)
callee = c.convertToken(child)
} else if child.Kind.IsType() {
arg = c.convertType(child)
}
}

if t := ast.NewTypeCall(node, name, arg); t != nil {
if t := ast.NewTypeCall(node, callee, arg); t != nil {
return t
}

return nil
}

func (c *converter) convertTypeofExpr(node cst.Node) ast.Expr {
var callee *ast.Token
var arg ast.Expr

for _, child := range node.Children {
if child.Kind == cst.IdentifierNode {
if callee == nil {
callee = c.convertToken(child)
} else {
arg = c.convertExpr(child)
}
} else if child.Kind.IsExpr() {
arg = c.convertExpr(child)
}
}

if t := ast.NewTypeof(node, callee, arg); t != nil {
return t
}

Expand Down
96 changes: 96 additions & 0 deletions core/ast/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type ExprVisitor interface {
VisitCast(expr *Cast)
VisitCall(expr *Call)
VisitTypeCall(expr *TypeCall)
VisitTypeof(expr *Typeof)
VisitStructInitializer(expr *StructInitializer)
VisitArrayInitializer(expr *ArrayInitializer)
VisitAllocateArray(expr *AllocateArray)
Expand Down Expand Up @@ -1011,6 +1012,101 @@ func (t *TypeCall) Result() *ExprResult {
return &t.result
}

// Typeof

type Typeof struct {
cst cst.Node
parent Node

Callee *Token
Arg Expr

result ExprResult
}

func NewTypeof(node cst.Node, callee *Token, arg Expr) *Typeof {
if callee == nil && arg == nil {
return nil
}

t := &Typeof{
cst: node,
Callee: callee,
Arg: arg,
}

if callee != nil {
callee.SetParent(t)
}
if arg != nil {
arg.SetParent(t)
}

return t
}

func (t *Typeof) Cst() *cst.Node {
if t.cst.Kind == cst.UnknownNode {
return nil
}

return &t.cst
}

func (t *Typeof) Token() scanner.Token {
return scanner.Token{}
}

func (t *Typeof) Parent() Node {
return t.parent
}

func (t *Typeof) SetParent(parent Node) {
if parent != nil && t.parent != nil {
panic("ast.Typeof.SetParent() - Parent is already set")
}

t.parent = parent
}

func (t *Typeof) AcceptChildren(visitor Visitor) {
if t.Callee != nil {
visitor.VisitNode(t.Callee)
}
if t.Arg != nil {
visitor.VisitNode(t.Arg)
}
}

func (t *Typeof) Clone() Node {
t2 := &Typeof{
cst: t.cst,
}

if t.Callee != nil {
t2.Callee = t.Callee.Clone().(*Token)
t2.Callee.SetParent(t2)
}
if t.Arg != nil {
t2.Arg = t.Arg.Clone().(Expr)
t2.Arg.SetParent(t2)
}

return t2
}

func (t *Typeof) String() string {
return ""
}

func (t *Typeof) AcceptExpr(visitor ExprVisitor) {
visitor.VisitTypeof(t)
}

func (t *Typeof) Result() *ExprResult {
return &t.result
}

// StructInitializer

type StructInitializer struct {
Expand Down
2 changes: 2 additions & 0 deletions core/ast/other.go
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,8 @@ func IsNil(node Node) bool {
return node == nil
case *TypeCall:
return node == nil
case *Typeof:
return node == nil
case *StructInitializer:
return node == nil
case *ArrayInitializer:
Expand Down
19 changes: 19 additions & 0 deletions core/checker/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,14 @@ func (c *checker) VisitIdentifier(expr *ast.Identifier) {
return
}

// Primitive type
for kind := ast.Void; kind <= ast.F64; kind++ {
if expr.String() == kind.String() {
expr.Result().SetType(&ast.Primitive{Kind: kind})
return
}
}

// Global variable
if variable := c.resolver.GetVariable(expr.String()); variable != nil && variable.Type != nil {
expr.Result().SetValue(variable.Type, ast.AssignableFlag|ast.AddressableFlag, variable)
Expand Down Expand Up @@ -556,6 +564,17 @@ func (c *checker) VisitTypeCall(expr *ast.TypeCall) {
expr.Result().SetValue(&ast.Primitive{Kind: ast.I32}, 0, nil)
}

func (c *checker) VisitTypeof(expr *ast.Typeof) {
expr.AcceptChildren(c)

expr.Result().SetValue(&ast.Primitive{Kind: ast.U32}, 0, nil)

// Check arg
if expr.Arg != nil && expr.Arg.Result().Kind == ast.InvalidResultKind {
c.error(expr.Arg, "Invalid expression")
}
}

func (c *checker) VisitCall(expr *ast.Call) {
expr.AcceptChildren(c)

Expand Down
4 changes: 3 additions & 1 deletion core/codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
)

type codegen struct {
ctx *Context
path string
resolver *ast.CombinedResolver

Expand Down Expand Up @@ -36,9 +37,10 @@ type exprValue struct {
addressable bool
}

func Emit(path string, root ast.RootResolver, file *ast.File) *ir.Module {
func Emit(ctx *Context, path string, root ast.RootResolver, file *ast.File) *ir.Module {
// Init codegen
c := &codegen{
ctx: ctx,
path: path,
resolver: ast.NewCombinedResolver(root),

Expand Down
29 changes: 29 additions & 0 deletions core/codegen/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package codegen

import "fireball/core/ast"

type typeId struct {
type_ ast.Type
id uint32
}

type Context struct {
typeIds []typeId
}

func (c *Context) GetTypeID(type_ ast.Type) uint32 {
// Check cache
for _, id := range c.typeIds {
if id.type_.Equals(type_) {
return id.id
}
}

// Insert into cache
c.typeIds = append(c.typeIds, typeId{
type_: type_,
id: uint32(len(c.typeIds)),
})

return uint32(len(c.typeIds) - 1)
}
7 changes: 7 additions & 0 deletions core/codegen/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,13 @@ func (c *codegen) VisitTypeCall(expr *ast.TypeCall) {
}}
}

func (c *codegen) VisitTypeof(expr *ast.Typeof) {
c.exprResult = exprValue{v: &ir.IntConst{
Typ: c.types.get(expr.Result().Type),
Value: ir.Unsigned(uint64(c.ctx.GetTypeID(expr.Arg.Result().Type))),
}}
}

func (c *codegen) VisitCall(expr *ast.Call) {
// Get type
callee := c.acceptExpr(expr.Callee)
Expand Down
16 changes: 16 additions & 0 deletions core/cst/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,22 @@ func parsePostfixExprPratt(p *parser, op scanner.TokenKind, lhs Node) Node {
return p.end()
}

// Typeof
if lhs.Token.Lexeme == "typeof" {
p.begin(TypeofExprNode)

p.childAdd(lhs)
p.advanceAddChild()
if p.child(parseExpr) {
return p.end()
}
if p.consume(scanner.RightParen) {
return p.end()
}

return p.end()
}

// Call
p.begin(CallExprNode)

Expand Down
3 changes: 3 additions & 0 deletions core/cst/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const (
IndexExprNode
CallExprNode
TypeCallExprNode
TypeofExprNode
StructExprNode
StructFieldExprNode
ArrayExprNode
Expand Down Expand Up @@ -243,6 +244,8 @@ func (n NodeKind) String() string {
return "Call"
case TypeCallExprNode:
return "Type call"
case TypeofExprNode:
return "Typeof"
case StructExprNode:
return "Struct"
case StructFieldExprNode:
Expand Down
5 changes: 5 additions & 0 deletions gen/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ var expressions = Group{
field("callee", type_("Token")),
field("arg", type_("Type")),
),
node(
"Typeof",
field("callee", type_("Token")),
field("arg", type_("Expr")),
),
node(
"StructInitializer",
field("new", type_("bool")),
Expand Down
2 changes: 1 addition & 1 deletion tests/src/implicit_casts.fb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func intPromotion() bool {
b = a;

var c = a + b;
return c == 10;
return typeof(c) == typeof(i32);
}

#[Test]
Expand Down
9 changes: 9 additions & 0 deletions tests/src/other.fb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Tests.Other;

struct Foo {}

#[Test("typeof")]
func _typeof() bool {
var a = 5;
return typeof(a) == typeof(i32);
}

0 comments on commit 6754eef

Please sign in to comment.