diff --git a/ast/nodes.go b/ast/nodes.go index a40aa11..5df9be9 100644 --- a/ast/nodes.go +++ b/ast/nodes.go @@ -329,6 +329,11 @@ type ( TokPos token.Pos // `for` token. } + Defer struct { + X Node + TokPos token.Pos // `defer` token. + } + Return struct { X Node // optional TokPos token.Pos // `return` token. @@ -367,8 +372,20 @@ func (n *While) PosEnd() token.Pos { return n.Body.PosEnd() } func (n *For) Pos() token.Pos { return n.TokPos } func (n *For) PosEnd() token.Pos { return n.Body.PosEnd() } -func (n *Return) Pos() token.Pos { return n.TokPos } -func (n *Return) PosEnd() token.Pos { return n.X.PosEnd() } +func (n *Defer) Pos() token.Pos { return n.TokPos } +func (n *Defer) PosEnd() token.Pos { return n.X.PosEnd() } + +func (n *Return) Pos() token.Pos { return n.TokPos } +func (n *Return) PosEnd() token.Pos { + if n.X != nil { + return n.X.PosEnd() + } + const length = len("return") - 1 + end := n.TokPos + end.Char += uint32(length) + end.Offset += uint64(length) + return end +} func (n *Break) Pos() token.Pos { return n.TokPos } func (n *Break) PosEnd() token.Pos { @@ -433,6 +450,7 @@ func (*If) implNode() {} func (*Else) implNode() {} func (*While) implNode() {} func (*For) implNode() {} +func (*Defer) implNode() {} func (*Return) implNode() {} func (*Break) implNode() {} func (*Continue) implNode() {} diff --git a/ast/operator_kind.go b/ast/operator_kind.go index 49db760..03edc60 100644 --- a/ast/operator_kind.go +++ b/ast/operator_kind.go @@ -10,20 +10,27 @@ const ( // Prefix. - OperatorNot // ! - OperatorNeg // - - OperatorAddrOf // & - OperatorPtr // * - OperatorEllipsis // ... + OperatorNot // ! + OperatorNeg // - + OperatorAddrOf // & + OperatorMutAddrOf // &mut + OperatorPtr // * + OperatorMutPtr // *mut + OperatorEllipsis // ... // Infix. OperatorAssign // = - OperatorAddAndAssign // += - OperatorSubAndAssign // -= - OperatorMultAndAssign // *= - OperatorDivAndAssign // /= - OperatorModAndAssign // %= + OperatorAddAssign // += + OperatorSubAssign // -= + OperatorMultAssign // *= + OperatorDivAssign // /= + OperatorModAssign // %= + OperatorBitAndAssign // &= + OperatorBitOrAssign // |= + OperatorBitXorAssign // ^= + OperatorBitShlAssign // <<= + OperatorBitShrAssign // >>= OperatorAdd // + OperatorSub // - OperatorMul // * diff --git a/ast/operator_kind_string.go b/ast/operator_kind_string.go index 72a6855..a960c4d 100644 --- a/ast/operator_kind_string.go +++ b/ast/operator_kind_string.go @@ -12,40 +12,47 @@ func _() { _ = x[OperatorNot-1] _ = x[OperatorNeg-2] _ = x[OperatorAddrOf-3] - _ = x[OperatorPtr-4] - _ = x[OperatorEllipsis-5] - _ = x[OperatorAssign-6] - _ = x[OperatorAddAndAssign-7] - _ = x[OperatorSubAndAssign-8] - _ = x[OperatorMultAndAssign-9] - _ = x[OperatorDivAndAssign-10] - _ = x[OperatorModAndAssign-11] - _ = x[OperatorAdd-12] - _ = x[OperatorSub-13] - _ = x[OperatorMul-14] - _ = x[OperatorDiv-15] - _ = x[OperatorMod-16] - _ = x[OperatorEq-17] - _ = x[OperatorNe-18] - _ = x[OperatorLt-19] - _ = x[OperatorLe-20] - _ = x[OperatorGt-21] - _ = x[OperatorGe-22] - _ = x[OperatorBitAnd-23] - _ = x[OperatorBitOr-24] - _ = x[OperatorBitXor-25] - _ = x[OperatorBitShl-26] - _ = x[OperatorBitShr-27] - _ = x[OperatorAnd-28] - _ = x[OperatorOr-29] - _ = x[OperatorAs-30] - _ = x[OperatorRangeInclusive-31] - _ = x[OperatorRangeExclusive-32] + _ = x[OperatorMutAddrOf-4] + _ = x[OperatorPtr-5] + _ = x[OperatorMutPtr-6] + _ = x[OperatorEllipsis-7] + _ = x[OperatorAssign-8] + _ = x[OperatorAddAssign-9] + _ = x[OperatorSubAssign-10] + _ = x[OperatorMultAssign-11] + _ = x[OperatorDivAssign-12] + _ = x[OperatorModAssign-13] + _ = x[OperatorBitAndAssign-14] + _ = x[OperatorBitOrAssign-15] + _ = x[OperatorBitXorAssign-16] + _ = x[OperatorBitShlAssign-17] + _ = x[OperatorBitShrAssign-18] + _ = x[OperatorAdd-19] + _ = x[OperatorSub-20] + _ = x[OperatorMul-21] + _ = x[OperatorDiv-22] + _ = x[OperatorMod-23] + _ = x[OperatorEq-24] + _ = x[OperatorNe-25] + _ = x[OperatorLt-26] + _ = x[OperatorLe-27] + _ = x[OperatorGt-28] + _ = x[OperatorGe-29] + _ = x[OperatorBitAnd-30] + _ = x[OperatorBitOr-31] + _ = x[OperatorBitXor-32] + _ = x[OperatorBitShl-33] + _ = x[OperatorBitShr-34] + _ = x[OperatorAnd-35] + _ = x[OperatorOr-36] + _ = x[OperatorAs-37] + _ = x[OperatorRangeInclusive-38] + _ = x[OperatorRangeExclusive-39] } -const _OperatorKind_name = "UnknownOperator!-&*...=+=-=*=/=%=+-*/%==!=<<=>>=&|^<<>>andoras....<" +const _OperatorKind_name = "UnknownOperator!-&&mut**mut...=+=-=*=/=%=&=|=^=<<=>>=+-*/%==!=<<=>>=&|^<<>>andoras....<" -var _OperatorKind_index = [...]uint8{0, 15, 16, 17, 18, 19, 22, 23, 25, 27, 29, 31, 33, 34, 35, 36, 37, 38, 40, 42, 43, 45, 46, 48, 49, 50, 51, 53, 55, 58, 60, 62, 64, 67} +var _OperatorKind_index = [...]uint8{0, 15, 16, 17, 18, 22, 23, 27, 30, 31, 33, 35, 37, 39, 41, 43, 45, 47, 50, 53, 54, 55, 56, 57, 58, 60, 62, 63, 65, 66, 68, 69, 70, 71, 73, 75, 78, 80, 82, 84, 87} func (i OperatorKind) String() string { if i >= OperatorKind(len(_OperatorKind_index)-1) { diff --git a/ast/repr.go b/ast/repr.go index e4b62f6..ed5e962 100644 --- a/ast/repr.go +++ b/ast/repr.go @@ -252,8 +252,16 @@ func (n *For) Repr() string { return fmt.Sprintf("for %s in %s %s", n.DeclList.Repr(), n.IterExpr.Repr(), n.Body.Repr()) } +func (n *Defer) Repr() string { + return fmt.Sprintf("defer %s", n.X.Repr()) +} + func (n *Return) Repr() string { - return fmt.Sprintf("return %s", n.X.Repr()) + if n.X != nil { + return fmt.Sprintf("return %s", n.X.Repr()) + } + + return "return" } func (n *Break) Repr() string { diff --git a/ast/walk.go b/ast/walk.go index 15cb3d9..050e3b6 100644 --- a/ast/walk.go +++ b/ast/walk.go @@ -188,6 +188,11 @@ func (v Visitor) WalkTopDown(tree Node) { v.WalkTopDown(n.IterExpr) v.WalkTopDown(n.Body) + case *Defer: + assert(n.X != nil) + + v.WalkTopDown(n.X) + case *Return: if n.X != nil { v.WalkTopDown(n.X) diff --git a/cgen/api.go b/cgen/api.go index 5618ad0..ee86355 100644 --- a/cgen/api.go +++ b/cgen/api.go @@ -12,6 +12,7 @@ func Generate(w io.Writer, m *checker.Module) error { gen := &generator{ Module: m, out: bufio.NewWriter(w), + scope: m.Scope, } gen.out.WriteString(prelude) @@ -20,7 +21,7 @@ func Generate(w io.Writer, m *checker.Module) error { panic(err) } - mainFn := gen.defs(gen.Defs, gen.Scope, false) + mainFn := gen.defs(gen.Defs, gen.Scope) gen.initFunc() if mainFn != nil { diff --git a/cgen/blocks.go b/cgen/blocks.go index 2634e01..62f4571 100644 --- a/cgen/blocks.go +++ b/cgen/blocks.go @@ -8,14 +8,65 @@ import ( func (gen *generator) block(list *ast.StmtList, result *checker.Var) { gen.line("{\n") gen.indent++ - for _, stmt := range list.Nodes[:len(list.Nodes)-1] { - gen.codeSect.WriteString(gen.StmtString(stmt)) - } - if result != nil { - gen.assign(gen.name(result), list.Nodes[len(list.Nodes)-1]) + + if _, ok := scopeIDs[gen.scope]; !ok { + scopeIDs[gen.scope] = 0 } else { - gen.codeSect.WriteString(gen.StmtString(list.Nodes[len(list.Nodes)-1])) + scopeIDs[gen.scope]++ + } + + id := scopeIDs[gen.scope] + scope := gen.scope.Children()[id] + + defer gen.setScope(gen.scope) + gen.setScope(scope) + + var deferNodes []*ast.Defer + + if len(list.Nodes) > 0 { + lastIdx := len(list.Nodes) - 1 + lastNode := list.Nodes[lastIdx] + + for _, stmt := range list.Nodes[:lastIdx] { + if deferNode, _ := stmt.(*ast.Defer); deferNode != nil { + println("deferred node: " + deferNode.Repr()) + deferNodes = append(deferNodes, deferNode) + continue + } + + gen.stmt(stmt) + } + + if result != nil { + gen.assign(gen.name(result), lastNode) + } else if deferNode, _ := lastNode.(*ast.Defer); deferNode != nil { + println("deferred node: " + deferNode.Repr()) + deferNodes = append(deferNodes, deferNode) + } else { + gen.stmt(lastNode) + } } + + for i := len(deferNodes) - 1; i >= 0; i-- { + gen.linef("L%d:;\n", gen.funcLabelID) + gen.funcLabelID++ + gen.stmt(deferNodes[i].X) + } + + delete(scopeIDs, gen.scope) gen.indent-- gen.line("}\n") } + +func scopePath(scope *checker.Scope) string { + buf := "" + buf = scope.Name() + + for s := scope.Parent(); s != nil; s = s.Parent() { + buf = s.Name() + " -> " + buf + } + + return buf +} + +var scopeIDs = map[*checker.Scope]int{} diff --git a/cgen/builtins.go b/cgen/builtins.go index d54c121..69bdee1 100644 --- a/cgen/builtins.go +++ b/cgen/builtins.go @@ -101,12 +101,13 @@ func (gen *generator) builtInPrintln(call *ast.Call) string { case types.KindUntypedString: if value.Value != nil { return fmt.Sprintf( - `fwrite(%[1]s"\n", 1, sizeof(%[1]s"\n"), stdout)`, + `fwrite(%[1]s"\n", 1, %d+1, stdout)`, value.Value, + len(*constant.AsString(value.Value)), ) } else { return fmt.Sprintf( - `fwrite(%[1]s"\n", 1, sizeof(%[1]s"\n"), stdout)`, + `fwrite(%[1]s, 1, strlen(%[1]s), stdout); fwrite("\n", 1, 1, stdout)`, gen.exprString(call.Args.Nodes[0]), ) } diff --git a/cgen/exprs.go b/cgen/exprs.go index ffb79ae..e6176ab 100644 --- a/cgen/exprs.go +++ b/cgen/exprs.go @@ -205,6 +205,9 @@ func (gen *generator) exprString(expr ast.Node) string { gen.block(node.StmtList, tmpVar) return gen.name(tmpVar) + case *ast.Defer: + return "" + default: fmt.Printf("not implemented '%T'\n", node) } @@ -215,7 +218,7 @@ func (gen *generator) exprString(expr ast.Node) string { func (gen *generator) unary(x ast.Node, _ types.Type, op ast.OperatorKind) string { switch op { - case ast.OperatorAddrOf: + case ast.OperatorAddrOf, ast.OperatorMutAddrOf: return fmt.Sprintf("(&%s)", gen.exprString(x)) case ast.OperatorNot: @@ -302,36 +305,66 @@ func (gen *generator) binary(x, y ast.Node, t types.Type, op ast.OperatorKind) s gen.exprString(y), ) - case ast.OperatorAddAndAssign: + case ast.OperatorAddAssign: return fmt.Sprintf("%s += %s", gen.exprString(x), gen.exprString(y), ) - case ast.OperatorSubAndAssign: + case ast.OperatorSubAssign: return fmt.Sprintf("%s -= %s", gen.exprString(x), gen.exprString(y), ) - case ast.OperatorMultAndAssign: + case ast.OperatorMultAssign: return fmt.Sprintf("%s *= %s", gen.exprString(x), gen.exprString(y), ) - case ast.OperatorDivAndAssign: + case ast.OperatorDivAssign: return fmt.Sprintf("%s /= %s", gen.exprString(x), gen.exprString(y), ) - case ast.OperatorModAndAssign: + case ast.OperatorModAssign: return fmt.Sprintf("%s %%= %s", gen.exprString(x), gen.exprString(y), ) + case ast.OperatorBitAndAssign: + return fmt.Sprintf("%s &= %s", + gen.exprString(x), + gen.exprString(y), + ) + + case ast.OperatorBitOrAssign: + return fmt.Sprintf("%s |= %s", + gen.exprString(x), + gen.exprString(y), + ) + + case ast.OperatorBitXorAssign: + return fmt.Sprintf("%s ^= %s", + gen.exprString(x), + gen.exprString(y), + ) + + case ast.OperatorBitShlAssign: + return fmt.Sprintf("%s <<= %s", + gen.exprString(x), + gen.exprString(y), + ) + + case ast.OperatorBitShrAssign: + return fmt.Sprintf("%s >>= %s", + gen.exprString(x), + gen.exprString(y), + ) + default: panic(fmt.Sprintf("not a binary operator: '%s'", op)) } diff --git a/cgen/functions.go b/cgen/functions.go index 1051e4a..713bfdb 100644 --- a/cgen/functions.go +++ b/cgen/functions.go @@ -10,9 +10,10 @@ import ( ) func (gen *generator) fn(sym *checker.Func) { - prevScope := gen.Scope - gen.Scope = sym.Local() + defer gen.setScope(gen.scope) + gen.setScope(sym.Local()) gen.funcTempVarId = 0 + gen.funcLabelID = 0 decl := "" tyResult := types.Type(nil) @@ -24,10 +25,9 @@ func (gen *generator) fn(sym *checker.Func) { } if !sym.IsExtern() { - gen.fnDef(sym, tyResult, decl) + gen.linef("%s\n", decl) + gen.fnDef(sym, tyResult) } - - gen.Scope = prevScope } func (gen *generator) fnDecl(sym *checker.Func) (decl string, tyResult types.Type) { @@ -71,7 +71,7 @@ func (gen *generator) fnDecl(sym *checker.Func) (decl string, tyResult types.Typ if len(sym.Params()) == 0 { if isArrayResult { buf.WriteString(fmt.Sprintf( - "%s result", + "%s __result", gen.TypeString(tyResult), )) } else { @@ -96,7 +96,7 @@ func (gen *generator) fnDecl(sym *checker.Func) (decl string, tyResult types.Typ if isArrayResult { buf.WriteString(fmt.Sprintf( - ", %s result", + ", %s __result", gen.TypeString(tyResult), )) } @@ -115,46 +115,27 @@ func (gen *generator) fnDecl(sym *checker.Func) (decl string, tyResult types.Typ return } -func (gen *generator) fnDef(sym *checker.Func, tyResult types.Type, decl string) { - isArrayResult := types.IsArray(tyResult) - gen.line(decl) - +func (gen *generator) fnDef(sym *checker.Func, tyResult types.Type) { node := sym.Node().(*ast.Decl) value, _ := node.Value.(*ast.Function) - var body []ast.Node - - if list, _ := value.Body.(*ast.CurlyList); list != nil { - body = list.StmtList.Nodes - } else { - body = []ast.Node{value.Body} - } - - gen.codeSect.WriteString(" {\n") + gen.line("{\n") gen.indent++ - if tyResult != nil && !isArrayResult { - gen.linef("%s result;\n", gen.TypeString(tyResult)) - } + resultVar := gen.resultVar(tyResult) if sym.Name() == "main" { gen.linef("init%s();\n", gen.Module.Name()) } - for i, stmt := range body { - if tyResult != nil && i == len(body)-1 { - if isArrayResult { - gen.arrayAssign("result", stmt, types.AsArray(tyResult)) - } else { - gen.linef("result = %s;\n", gen.exprString(stmt)) - } - } else { - gen.codeSect.WriteString(gen.StmtString(stmt)) - } + if list, _ := value.Body.(*ast.CurlyList); list != nil { + gen.block(list.StmtList, resultVar) + } else if resultVar != nil { + gen.assign("__result", value.Body) } - if tyResult != nil && !isArrayResult { - gen.line("return result;\n") + if resultVar != nil && !types.IsArray(tyResult) { + gen.line("return __result;\n") } gen.indent-- diff --git a/cgen/generator.go b/cgen/generator.go index 5e1d383..59038e7 100644 --- a/cgen/generator.go +++ b/cgen/generator.go @@ -15,7 +15,9 @@ import ( type generator struct { *checker.Module + scope *checker.Scope funcTempVarId int + funcLabelID int typeSect strings.Builder declVarsSect strings.Builder declFnsSect strings.Builder @@ -28,7 +30,6 @@ type generator struct { func (gen *generator) defs( defs *orderedmap.OrderedMap[*ast.Ident, checker.Symbol], owner *checker.Scope, - declOnly bool, ) (mainFunc *checker.Func) { for def := defs.Front(); def != nil; def = def.Next() { def := def.Value @@ -59,7 +60,7 @@ func (gen *generator) defs( } case *checker.Module: - gen.defs(sym.Defs, sym.Scope, true) + gen.defs(sym.Defs, sym.Scope) default: report.Warningf("not implemented (%T)", sym) @@ -69,6 +70,11 @@ func (gen *generator) defs( return mainFunc } +func (gen *generator) setScope(scope *checker.Scope) { + report.TaggedDebugf("cgen", "set scope: %s", scopePath(scope)) + gen.scope = scope +} + func (gen *generator) line(s string) { gen.fline(&gen.codeSect, s) } diff --git a/cgen/names.go b/cgen/names.go index 0cff325..cdbcd2a 100644 --- a/cgen/names.go +++ b/cgen/names.go @@ -15,6 +15,11 @@ func (gen *generator) name(sym checker.Symbol) string { } buf := strings.Builder{} + if strings.HasPrefix(sym.Name(), "__") { + names[sym] = sym.Name() + return sym.Name() + } + switch sym := sym.(type) { case *checker.Var: if sym.IsGlobal() { diff --git a/cgen/stmts.go b/cgen/stmts.go index f3349d2..40b4ba0 100644 --- a/cgen/stmts.go +++ b/cgen/stmts.go @@ -2,14 +2,15 @@ package cgen import ( "github.com/saffage/jet/ast" + "github.com/saffage/jet/internal/report" "github.com/saffage/jet/types" ) -func (gen *generator) StmtString(stmt ast.Node) string { +func (gen *generator) stmt(stmt ast.Node) { + report.Debugf("stmt = %s", stmt.Repr()) switch stmt := stmt.(type) { case *ast.Empty: gen.line("\n") - return "" case *ast.Decl: if !stmt.IsVar { @@ -22,13 +23,8 @@ func (gen *generator) StmtString(stmt ast.Node) string { gen.decl(sym) case *ast.While: - gen.linef("while (%s) {\n", gen.exprString(stmt.Cond)) - gen.indent++ - for _, stmt := range stmt.Body.Nodes { - gen.codeSect.WriteString(gen.StmtString(stmt)) - } - gen.indent-- - gen.linef("}\n") + gen.linef("while (%s)\n", gen.exprString(stmt.Cond)) + gen.block(stmt.Body.StmtList, nil) case *ast.For: loopVar := gen.SymbolOf(stmt.DeclList.Nodes[0].(*ast.Decl).Ident) @@ -38,18 +34,13 @@ func (gen *generator) StmtString(stmt ast.Node) string { cmpOp = ast.OperatorLe } gen.linef( - "for (%[1]s %[2]s=%[3]s; %[4]s; %[2]s+=1) {\n", + "for (%[1]s %[2]s=%[3]s; %[4]s; %[2]s+=1)\n", gen.TypeString(loopVar.Type()), gen.name(loopVar), gen.exprString(iterExpr.X), gen.binary(loopVar.Ident(), iterExpr.Y, types.Bool, cmpOp), ) - gen.indent++ - for _, stmt := range stmt.Body.Nodes { - gen.codeSect.WriteString(gen.StmtString(stmt)) - } - gen.indent-- - gen.line("}\n") + gen.block(stmt.Body.StmtList, nil) case *ast.If: gen.ifExpr(stmt, nil) @@ -84,6 +75,4 @@ func (gen *generator) StmtString(stmt ast.Node) string { } } } - - return "" } diff --git a/cgen/vars.go b/cgen/vars.go index 02d4aa3..c2b0419 100644 --- a/cgen/vars.go +++ b/cgen/vars.go @@ -20,15 +20,28 @@ func (gen *generator) varDecl(sym *checker.Var) string { func (gen *generator) tempVar(ty types.Type) *checker.Var { id := fmt.Sprintf("tmp__%d", gen.funcTempVarId) decl := &ast.Decl{Ident: &ast.Ident{Name: id}} - sym := checker.NewVar(gen.Scope, ty, decl) + sym := checker.NewVar(gen.scope, ty, decl) gen.line(gen.varDecl(sym)) - _ = gen.Scope.Define(sym) + _ = gen.scope.Define(sym) gen.funcTempVarId++ return sym } +func (gen *generator) resultVar(ty types.Type) *checker.Var { + if ty == nil { + return nil + } + decl := &ast.Decl{Ident: &ast.Ident{Name: "__result"}} + sym := checker.NewVar(gen.scope, ty, decl) + if !types.IsArray(ty) { + gen.linef("%s __result;\n", gen.TypeString(ty)) + } + _ = gen.scope.Define(sym) + return sym +} + func (gen *generator) initFunc() { - gen.linef("void init%s(void) {\n", gen.Module.Name()) + gen.linef("void init%s(void)\n{\n", gen.Module.Name()) gen.indent++ for def := gen.Defs.Front(); def != nil; def = def.Next() { @@ -45,5 +58,5 @@ func (gen *generator) initFunc() { } gen.indent-- - gen.linef("}\n") + gen.line("}\n") } diff --git a/checker/func.go b/checker/func.go index 23bb178..ae8be54 100644 --- a/checker/func.go +++ b/checker/func.go @@ -213,7 +213,7 @@ func (check *Checker) resolveFuncBody( return nil } - if tyFunc.Result() == nil { + if !hasResult { return types.NewFunc(tyFunc.Params(), tyBody, tyFunc.Variadic()) } diff --git a/checker/operators.go b/checker/operators.go index 4b691ed..d3af2d3 100644 --- a/checker/operators.go +++ b/checker/operators.go @@ -26,7 +26,7 @@ func (check *Checker) prefix(node *ast.Op, tyOperand types.Type) types.Type { } } - case ast.OperatorAddrOf: + case ast.OperatorAddrOf, ast.OperatorMutAddrOf: switch operand := node.Y.(type) { case *ast.Ident: if sym, _ := check.symbolOf(operand).(*Var); sym != nil { @@ -50,7 +50,7 @@ func (check *Checker) prefix(node *ast.Op, tyOperand types.Type) types.Type { check.errorf(node.Y, "expression is not an addressable location") return nil - case ast.OperatorPtr: + case ast.OperatorPtr, ast.OperatorMutPtr: if !types.IsTypeDesc(tyOperand) { check.errorf(node.Y, "expression is not a type") return nil @@ -144,10 +144,10 @@ func (check *Checker) infixPrimitive( return tOperandX } - case ast.OperatorAddAndAssign, - ast.OperatorSubAndAssign, - ast.OperatorMultAndAssign, - ast.OperatorDivAndAssign: + case ast.OperatorAddAssign, + ast.OperatorSubAssign, + ast.OperatorMultAssign, + ast.OperatorDivAssign: switch tOperandX.Kind() { case types.KindUntypedInt, types.KindUntypedFloat, @@ -186,7 +186,12 @@ func (check *Checker) infixPrimitive( return tOperandX } - case ast.OperatorModAndAssign: + case ast.OperatorModAssign, + ast.OperatorBitAndAssign, + ast.OperatorBitOrAssign, + ast.OperatorBitXorAssign, + ast.OperatorBitShlAssign, + ast.OperatorBitShrAssign: switch tOperandX.Kind() { case types.KindUntypedInt, types.KindI8, diff --git a/checker/scope.go b/checker/scope.go index fd9ffc5..9bd1d7c 100644 --- a/checker/scope.go +++ b/checker/scope.go @@ -1,23 +1,29 @@ package checker -import "github.com/saffage/jet/ast" +import ( + "github.com/saffage/jet/ast" +) var Global = NewScope(nil, "global") type Scope struct { - parent *Scope - name string - symbols map[string]Symbol + name string + parentID int + parent *Scope + children []*Scope + defers []*ast.Defer + symbols map[string]Symbol } func NewScope(parent *Scope, name string) *Scope { - return &Scope{parent, name, nil} -} + scope := &Scope{name: name, parent: parent} -// Returns the scope in which the current scope was defined, -// or nil if the current scope has no parent. -func (scope *Scope) Parent() *Scope { - return scope.parent + if parent != nil && parent.parent != nil { + scope.parentID = len(parent.children) + parent.children = append(parent.children, scope) + } + + return scope } // Returns a name of the scope. Used in code generator. @@ -33,19 +39,27 @@ func (scope *Scope) Name() string { return scope.name } -// Defines a symbol in the scope. If a symbol with the same -// name is already defined in this scope, it will return it -// without overriding it. -// -// NOTE: the symbol will be defined even if a symbol with the -// same name is defined in the parent scope. -func (scope *Scope) Define(symbol Symbol) (defined Symbol) { - // Scope should not contain a nil symbols. +func (scope *Scope) Parent() *Scope { + return scope.parent +} + +func (scope *Scope) Children() []*Scope { + return scope.children +} + +func (scope *Scope) Defers() []*ast.Defer { + return scope.defers +} + +// Defines a new symbol in the scope. If a symbol with the same +// name is already defined in this scope, it will return error. +func (scope *Scope) Define(symbol Symbol) Symbol { if symbol == nil { + // Scope should not contain a nil symbols. panic("attempt to define nil symbol") } - if defined := scope.Member(symbol.Name()); defined != nil { + if defined := scope.LookupLocal(symbol.Name()); defined != nil { return defined } @@ -61,7 +75,7 @@ func (scope *Scope) Define(symbol Symbol) (defined Symbol) { // the specified scope and returns it, or nil if such symbol // is undefined or unavailable (private). func (scope *Scope) Lookup(name string) (Symbol, *Scope) { - if member := scope.Member(name); member != nil { + if member := scope.LookupLocal(name); member != nil { return member, scope } @@ -75,12 +89,12 @@ func (scope *Scope) Lookup(name string) (Symbol, *Scope) { // Searches for the specified symbol by name in the specified // scope and returns it, or nil if no such symbol is defined // in the current scope. -func (scope *Scope) Member(name string) Symbol { - if symbol, ok := scope.symbols[name]; ok { - return symbol +func (scope *Scope) LookupLocal(name string) Symbol { + if scope.symbols == nil { + return nil } - return nil + return scope.symbols[name] } func errorAlreadyDefined(ident, previous *ast.Ident) *Error { diff --git a/checker/type_alias.go b/checker/type_alias.go index 63dfc5e..1175cb0 100644 --- a/checker/type_alias.go +++ b/checker/type_alias.go @@ -2,6 +2,7 @@ package checker import ( "github.com/saffage/jet/ast" + "github.com/saffage/jet/internal/report" "github.com/saffage/jet/types" ) @@ -49,4 +50,5 @@ func (check *Checker) resolveTypeAliasDecl(decl *ast.Decl) { check.newDef(decl.Ident, sym) check.setType(decl, typedesc) + report.TaggedDebugf("checker", "alias: set type: %s", typedesc) } diff --git a/checker/type_resolver.go b/checker/type_resolver.go index 69b5371..4cf1dd7 100644 --- a/checker/type_resolver.go +++ b/checker/type_resolver.go @@ -82,6 +82,13 @@ func (check *Checker) typeOfInternal(expr ast.Node) types.Type { case *ast.For: return check.typeOfFor(node) + case *ast.Defer: + return check.typeOfDefer(node) + + case *ast.Return: + check.errorf(node, "'return' statement are not implemented") + return types.Unit + // NOTE implementation of break & continue are not finished. case *ast.Break: if node.Label != nil { @@ -681,3 +688,15 @@ func (check *Checker) typeOfFor(node *ast.For) (ty types.Type) { return } + +func (check *Checker) typeOfDefer(node *ast.Defer) (ty types.Type) { + ty = types.Unit + check.scope.defers = append(check.scope.defers, node) + + tyX := check.typeOf(node.X) + if tyX == nil { + return + } + + return +} diff --git a/checker/value.go b/checker/value.go index 6fe4197..6c44e1d 100644 --- a/checker/value.go +++ b/checker/value.go @@ -434,7 +434,7 @@ func compileUnaryOp(x constant.Value, opKind ast.OperatorKind) constant.Value { panic("unreachable") } - case ast.OperatorAddrOf: + case ast.OperatorAddrOf, ast.OperatorMutAddrOf: panic("pointer operation cannot be evaluated at compile-time") default: diff --git a/examples/defer.jet b/examples/defer.jet new file mode 100644 index 0000000..fe3d7f4 --- /dev/null +++ b/examples/defer.jet @@ -0,0 +1,31 @@ +i := 0 + +ok :: () if i < 5 { i += 1; true } else { false } + +main :: () { + defer $println("deferred main 1") + defer $println("deferred main 2") + $println("main") + + { + defer $println("deferred nested") + $println("nested") + } + + for i in 0..5 { + $println(i) + + defer { + $print("deferred for: ") + $println(i) + } + } + + while ok() { + $println("ok") + + defer { + $println("deferred while") + } + } +} \ No newline at end of file diff --git a/examples/game_of_life.jet b/examples/game_of_life.jet index 978e62f..9e8cd59 100644 --- a/examples/game_of_life.jet +++ b/examples/game_of_life.jet @@ -56,13 +56,10 @@ next_field :: () { for row in 0 ..< HEIGHT { for col in 0 ..< WIDTH { neighbors := count_neighbors(row, col) - # NOTE current parser fails here - hidden_field[row][col] = { - if field[row][col] { - neighbors == 2 or neighbors == 3 - } else { - neighbors == 3 - } + hidden_field[row][col] = if field[row][col] { + neighbors == 2 or neighbors == 3 + } else { + neighbors == 3 } } } diff --git a/examples/ifelse.jet b/examples/if_else.jet similarity index 100% rename from examples/ifelse.jet rename to examples/if_else.jet diff --git a/examples/pointers.jet b/examples/pointers.jet index 477bac5..0af788a 100644 --- a/examples/pointers.jet +++ b/examples/pointers.jet @@ -8,9 +8,10 @@ main :: () { $assert(t.field == 12) } { - x := 1 + x := [1, 2] y := &x - i := $size_of(int) - { { y as u64 + i as u64 } as *u8 }.* = 1 + { { { y as u64 } + $size_of(int) } as *int }.* = 1 + $assert(x[0] == 1) + $assert(x[1] == 1) } } diff --git a/examples/tetris.jet b/examples/tetris.jet index fa94607..944de2b 100644 --- a/examples/tetris.jet +++ b/examples/tetris.jet @@ -229,13 +229,13 @@ shuffle :: (shuffler: *Shuffler) { } next_tetramino :: (tetramino: *Tetramino_Instance, shuffler: *Shuffler) { - $assert(shuffler != 0 as *Shuffler) + $assert(shuffler != { 0 as *Shuffler }) if shuffler.*.index == NUM_TETRAMINOES { shuffle(shuffler) shuffler.*.index = 0 } - $assert(tetramino != 0 as *Tetramino_Instance) + $assert(tetramino != { 0 as *Tetramino_Instance }) tetramino.*.rotation = 0 tetramino.*.x = 3 tetramino.*.y = 20 @@ -309,10 +309,10 @@ render_cell :: (x: int, y: int, color: Color) { cell_x := PADDING_X + x * CELL_SIZE cell_y := SCREEN_HEIGHT - PADDING_Y - { y + 1 } * CELL_SIZE cell := Rectangle( - x = cell_x as f32 + 0.5, - y = cell_y as f32 + 0.5, - width = CELL_SIZE as f32 - 0.5, - height = CELL_SIZE as f32 - 0.5, + x = { cell_x as f32 } + 0.5, + y = { cell_y as f32 } + 0.5, + width = { CELL_SIZE as f32 } - 0.5, + height = { CELL_SIZE as f32 } - 0.5, ) draw_rectangle_rec(cell, color) } @@ -329,19 +329,19 @@ render_grid :: () { for i in 0.. [8]u8 { - $assert(instance != 0 as *Tetramino_Instance) + $assert(instance != { 0 as *Tetramino_Instance }) coords: [8]u8 i := 0 for y in 0..<4 { - row: u32 = instance.*.tetramino.rotations[instance.*.rotation] >> y as u32 * 4 + row: u32 = instance.*.tetramino.rotations[instance.*.rotation] >> { y as u32 } * 4 for x in 0..<4 { if row&0x1 != 0 { _x := instance.*.x + x diff --git a/parser/errors.go b/parser/errors.go index 8089229..6c35512 100644 --- a/parser/errors.go +++ b/parser/errors.go @@ -3,7 +3,6 @@ package parser import ( "errors" "fmt" - "slices" "strings" "github.com/saffage/jet/internal/report" @@ -139,43 +138,3 @@ func (p *parser) errorExpectedTokenAt(start, end token.Pos, tokens ...token.Kind Message: fmt.Sprintf("want %s, got %s instead", buf.String(), p.tok.Kind.UserString()), }) } - -func (p *parser) skip(to ...token.Kind) (start, end token.Pos) { - if len(to) == 0 { - to = endOfExprKinds - } - - start = p.tok.Start - - for p.tok.Kind != token.EOF && !slices.Contains(to, p.tok.Kind) { - end = p.tok.End - p.next() - } - - if p.flags&Trace != 0 && end.IsValid() { - // TODO must be removed - warn := Error{ - Start: start, - End: end, - Message: "tokens was skipped for some reason", - isWarn: true, - isInternal: true, - } - p.errors = append(p.errors, warn) - } - - return -} - -var ( - endOfStmtKinds = []token.Kind{ - token.Semicolon, - token.NewLine, - } - endOfExprKinds = append(endOfStmtKinds, []token.Kind{ - token.Comma, - token.RParen, - token.RCurly, - token.RBracket, - }...) -) diff --git a/parser/grammar.ebnf b/parser/grammar.ebnf index 6ac3362..cffde35 100644 --- a/parser/grammar.ebnf +++ b/parser/grammar.ebnf @@ -6,7 +6,7 @@ stmt_list = stmt, {stmt_sep, stmt}, [stmt_sep] ; decl_list = decl, {stmt_sep, decl}, [stmt_sep] ; expr_list = expr, {',', expr}, [','] ; -type = expr ; +type = '...' | ['...'], simple_expr ; stmt = {'\n'}, (';' | decl | expr) ; decl = [attribute_list, {'\n'}], ['mut'], ident, ':', (type | [type], '=', expr) ; @@ -15,45 +15,56 @@ short_decl = [attribute_list, {'\n'}], ['mut'], ident, [':', (type | [type] short_decl_list = short_decl, {stmt_sep, short_decl}, [stmt_sep] ; attribute_list = '@', '[', [ident, {'.', ident}, paren_list], ']' ; -expr = function | struct | enum | return | break | continue | while | assign_expr ; -assign_expr = bool_or_expr, {assign_op, bool_or_expr} ; -bool_or_expr = bool_and_expr, {'or', bool_and_expr} ; -bool_and_expr = compare_expr, {'and', compare_expr} ; +expr = defer | return | break | continue | assign_op | simple_expr ; +simple_expr = function | as_expr ; +assign_expr = ident, {assign_op, as_expr} ; +as_expr = range_expr, {as_op, range_expr} ; +range_expr = bool_or_expr, {range_op, bool_or_expr} ; +bool_or_expr = bool_and_expr, {bool_or_op, bool_and_expr} ; +bool_and_expr = compare_expr, {bool_and_op, compare_expr} ; compare_expr = bitwise_expr, {compare_op, bitwise_expr} ; bitwise_expr = bit_shift_expr, {bitwise_op, bit_shift_expr} ; bit_shift_expr = addition_expr, {bit_shift_op, addition_expr} ; addition_expr = multiply_expr, {addition_op, multiply_expr} ; multiply_expr = primary_expr, {multiply_op, primary_expr} ; +primary_expr = {prefix_op}, operand, {dot_op | bracket_list | paren_list}; -primary_expr = {prefix_op}, operand, {primary_expr_suffix} | if; -primary_expr_suffix = '.', ident | '.*' | bracket_list | paren_list ; +operand = ident | literal | builtin_call | if | while | for | struct | enum | block | bracket_list | paren_list; +literal = int_literal | float_literal | string_literal ; assign_op = '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '<<=' | '>>=' ; +as_op = 'as' ; +range_op = '..' | '..<' ; +bool_or_op = 'or' ; +bool_and_op = 'and' ; compare_op = '>=' | '>' | '<=' | '<' | '==' | '!=' ; bitwise_op = '&' | '|', '^' ; bit_shift_op = '<<' | '>>' ; addition_op = '+' | '-' ; multiply_op = '*' | '/' | '%' ; -prefix_op = '!' | '-' | '*', ['mut'] | bracket_list ; + +dot_op = '.', ('*' | ident) ; +prefix_op = '!' | '-' | ref_or_ptr | bracket_list ; +ref_or_ptr = ('&' | '*'), ['mut'] ; paren_list = '(', [expr_list], ')' ; bracket_list = '[', [expr_list], ']' ; block = '{', [stmt_list], '}' ; -function = paren_list, (expr | '->', type, block) ; +function = paren_list, (expr | '->', type, [block]) ; builtin_call = '$', ident, [paren_list] ; -if = 'if', expr, block, [else] ; +if = 'if', simple_expr, block, [else] ; else = 'else', (if | block) ; -while = 'while', expr, block ; -return = 'return', [expr] ; -break = 'break' ; -continue = 'continue' ; +while = 'while', simple_expr, block ; +for = 'for', decl, 'in', simple_expr, block ; +defer = 'defer', simple_expr ; +return = 'return', [simple_expr] ; +break = 'break', [label] ; +continue = 'continue', [label] ; struct = 'struct', '{', [decl_list], '}' ; enum = 'enum', '{', [short_decl_list], '}' ; -operand = ident | literal | block | paren_list | builtin_call ; -literal = int_literal | float_literal | string_literal ; - +label = ident ; ident = ident_start_char, {ident_char} ; ident_start_char = letter | '_' ; ident_char = letter | digit | '_' ; diff --git a/parser/parse_ast.go b/parser/parse_ast.go index ce66ea1..317c291 100644 --- a/parser/parse_ast.go +++ b/parser/parse_ast.go @@ -1,8 +1,6 @@ package parser import ( - "slices" - "github.com/saffage/jet/ast" "github.com/saffage/jet/token" ) @@ -95,45 +93,59 @@ func (p *parser) parseExpr() ast.Node { } switch p.tok.Kind { - case token.KwIf: - return p.parseIf() - - case token.KwWhile: - return p.parseWhile() - - case token.KwFor: - return p.parseFor() + case token.KwDefer: + return p.parseDefer() case token.KwReturn: return p.parseReturn() - case token.KwBreak, token.KwContinue: - return p.parseBreakOrContinue() + case token.KwBreak: + return p.parseBreak() + + case token.KwContinue: + return p.parseContinue() default: - return p.parseSimpleExpr() + return p.parseSimpleExpr(true) } } -func (p *parser) parseSimpleExpr() ast.Node { +func (p *parser) parseSimpleExpr(allowAssign bool) ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) } - return p.parseBinaryExpr(nil, 1) + var x ast.Node + + if p.tok.Kind == token.LParen { + params := p.parseParenList(p.declOr(p.parseExpr)) + if params == nil { + return nil + } + + if p.match(token.Arrow) || p.match(exprStartKinds...) { + return p.parseFunction(params) + } + + x = params + } + + if allowAssign { + return p.parseBinaryExpr(x, 1) + } + + return p.parseBinaryExpr(x, 2) } -func (p *parser) parseBinaryExpr(lhs ast.Node, precedence int) ast.Node { +func (p *parser) parseBinaryExpr(x ast.Node, precedence int) ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) } - if lhs == nil { - lhs = p.parseUnaryExpr() - } - - if lhs == nil { - return nil + if x == nil { + if x = p.parsePrimaryExpr(); x == nil { + return nil + } } for p.tok.Precedence() >= precedence { @@ -143,94 +155,13 @@ func (p *parser) parseBinaryExpr(lhs ast.Node, precedence int) ast.Node { p.next() } - rhs := p.parseBinaryExpr(nil, tok.Precedence()+1) - - if rhs == nil { + y := p.parseBinaryExpr(nil, tok.Precedence()+1) + if y == nil { return nil } - binaryOpKind := ast.UnknownOperator - - switch tok.Kind { - case token.Plus: - binaryOpKind = ast.OperatorAdd - - case token.Minus: - binaryOpKind = ast.OperatorSub - - case token.Asterisk: - binaryOpKind = ast.OperatorMul - - case token.Slash: - binaryOpKind = ast.OperatorDiv - - case token.Percent: - binaryOpKind = ast.OperatorMod - - case token.Eq: - binaryOpKind = ast.OperatorAssign - - case token.PlusEq: - binaryOpKind = ast.OperatorAddAndAssign - - case token.MinusEq: - binaryOpKind = ast.OperatorSubAndAssign - - case token.AsteriskEq: - binaryOpKind = ast.OperatorMultAndAssign - - case token.SlashEq: - binaryOpKind = ast.OperatorDivAndAssign - - case token.PercentEq: - binaryOpKind = ast.OperatorModAndAssign - - case token.EqOp: - binaryOpKind = ast.OperatorEq - - case token.NeOp: - binaryOpKind = ast.OperatorNe - - case token.LtOp: - binaryOpKind = ast.OperatorLt - - case token.LeOp: - binaryOpKind = ast.OperatorLe - - case token.GtOp: - binaryOpKind = ast.OperatorGt - - case token.GeOp: - binaryOpKind = ast.OperatorGe - - case token.Amp: - binaryOpKind = ast.OperatorBitAnd - - case token.Pipe: - binaryOpKind = ast.OperatorBitOr - - case token.Caret: - binaryOpKind = ast.OperatorBitXor - - case token.Shl: - binaryOpKind = ast.OperatorBitShl - - case token.Shr: - binaryOpKind = ast.OperatorBitShr - - case token.KwAnd: - binaryOpKind = ast.OperatorAnd - - case token.KwOr: - binaryOpKind = ast.OperatorOr - - case token.Dot2: - binaryOpKind = ast.OperatorRangeInclusive - - case token.Dot2Less: - binaryOpKind = ast.OperatorRangeExclusive - - default: + binaryOpKind, ok := operators[tok.Kind] + if !ok { p.errorfAt( ErrorInvalidBinaryOperator, tok.Start, @@ -240,19 +171,27 @@ func (p *parser) parseBinaryExpr(lhs ast.Node, precedence int) ast.Node { ) } - lhs = &ast.Op{ - X: lhs, - Y: rhs, + x = &ast.Op{ + X: x, + Y: y, Start: tok.Start, End: tok.End, Kind: binaryOpKind, } } - return lhs + return x } -func (p *parser) parseUnaryExpr() ast.Node { +func (p *parser) parsePrimaryExpr() ast.Node { + if p.flags&Trace != 0 { + defer un(trace(p)) + } + + return p.parsePrefixExpr() +} + +func (p *parser) parsePrefixExpr() ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) } @@ -263,7 +202,7 @@ func (p *parser) parseUnaryExpr() ast.Node { return &ast.Op{ X: nil, - Y: p.parseUnaryExpr(), + Y: p.parsePrefixExpr(), Start: minus.Start, End: minus.End, Kind: ast.OperatorNeg, @@ -274,7 +213,7 @@ func (p *parser) parseUnaryExpr() ast.Node { return &ast.Op{ X: nil, - Y: p.parseUnaryExpr(), + Y: p.parsePrefixExpr(), Start: bang.Start, End: bang.End, Kind: ast.OperatorNot, @@ -283,9 +222,19 @@ func (p *parser) parseUnaryExpr() ast.Node { case token.Asterisk: asterisk := p.consume() + if tokMut := p.consume(token.KwMut); tokMut != nil { + return &ast.Op{ + X: nil, + Y: p.parsePrefixExpr(), + Start: asterisk.Start, + End: tokMut.End, + Kind: ast.OperatorMutPtr, + } + } + return &ast.Op{ X: nil, - Y: p.parseUnaryExpr(), + Y: p.parsePrefixExpr(), Start: asterisk.Start, End: asterisk.End, Kind: ast.OperatorPtr, @@ -294,44 +243,42 @@ func (p *parser) parseUnaryExpr() ast.Node { case token.Amp: amp := p.consume() - // if varTok := p.consume(token.KwVar); varTok != nil { - // return &ast.PrefixOp{ - // X: p.parseUnaryExpr(), - // Opr: &ast.Operator{ - // Start: loc, - // End: varTok.End, - // Kind: ast.OperatorMutAddr, - // }, - // } - // } + if tokMut := p.consume(token.KwMut); tokMut != nil { + return &ast.Op{ + X: nil, + Y: p.parsePrefixExpr(), + Start: amp.Start, + End: tokMut.End, + Kind: ast.OperatorMutAddrOf, + } + } return &ast.Op{ X: nil, - Y: p.parseUnaryExpr(), + Y: p.parsePrefixExpr(), Start: amp.Start, End: amp.End, Kind: ast.OperatorAddrOf, } - default: - return p.parsePrimaryExpr(nil) - } -} + case token.LBracket: + list := p.parseBracketList(p.parseExpr) + if list == nil { + return nil + } -func (p *parser) parsePrimaryExpr(x ast.Node) ast.Node { - if p.flags&Trace != 0 { - defer un(trace(p)) - } + if p.match(simpleExprStartKinds...) { + return &ast.ArrayType{ + X: p.parsePrefixExpr(), + Args: list, + } + } - if x == nil { - x = p.parseOperand() - } + return list - if x == nil { - return nil + default: + return p.parseSuffixExpr(nil) } - - return p.parseSuffixExpr(x) } func (p *parser) parseSuffixExpr(x ast.Node) ast.Node { @@ -340,7 +287,9 @@ func (p *parser) parseSuffixExpr(x ast.Node) ast.Node { } if x == nil { - x = p.parseOperand() + if x = p.parseOperand(); x == nil { + return nil + } } for { @@ -352,34 +301,6 @@ func (p *parser) parseSuffixExpr(x ast.Node) ast.Node { case token.Dot: x = p.parseDot(x) - // case token.Amp, token.Asterisk: - // before := p.save() - // tok := p.consume() - - // if !p.isExprStart(p.tok.Kind) { - // oprKind := ast.UnknownOperator - - // switch tok.Kind { - // case token.Asterisk: - // oprKind = ast.OperatorDeref - - // case token.Amp: - // oprKind = ast.OperatorAddrOf - // } - - // x = &ast.PostfixOp{ - // X: x, - // Opr: &ast.Operator{ - // Start: tok.Start, - // End: tok.End, - // Kind: oprKind, - // }, - // } - // } else { - // p.restore(before) - // return x - // } - case token.LBracket: x = &ast.Index{ X: x, @@ -392,17 +313,6 @@ func (p *parser) parseSuffixExpr(x ast.Node) ast.Node { Args: p.parseParenList(p.declOr(p.parseExpr)), } - case token.KwAs: - asTok := p.consume() - - x = &ast.Op{ - X: x, - Y: p.parseType(), - Start: asTok.Start, - End: asTok.End, - Kind: ast.OperatorAs, - } - default: return x } @@ -418,77 +328,109 @@ func (p *parser) parseOperand() ast.Node { case token.Ident: return p.parseIdent() - case token.Dollar: - return p.parseBuiltIn() - case token.Int, token.Float, token.String: return p.parseLiteral() - case token.LParen: - operand := p.parseParenList(p.declOr(p.parseExpr)) - if p.match(token.Arrow) || !p.match(append(endOfExprKinds, token.EOF)...) { - return p.parseFunction(operand) - } - return operand + case token.Dollar: + return p.parseBuiltIn() - case token.LCurly: - return p.parseBlock() + case token.KwIf: + return p.parseIf() - case token.LBracket: - if list := p.parseBracketList(p.parseExpr); list != nil { - return list - } - return nil + case token.KwWhile: + return p.parseWhile() + + case token.KwFor: + return p.parseFor() case token.KwStruct: - // NOTE needed for expressions like `struct{}()` return p.parseStructType() case token.KwEnum: - // NOTE needed for expressions like `enum{}.Foo` return p.parseEnumType() - default: - p.error(ErrorExpectedOperand) - return nil + case token.LCurly: + if block := p.parseBlock(); block != nil { + return block + } + + case token.LBracket: + if list := p.parseBracketList(p.parseExpr); list != nil { + return list + } + + case token.LParen: + if list := p.parseParenList(p.declOr(p.parseExpr)); list != nil { + return list + } } + + p.error(ErrorExpectedOperand) + return nil } //------------------------------------------------ // Complex expressions //------------------------------------------------ -func (p *parser) parseFunction(params *ast.ParenList) ast.Node { +func (p *parser) parseEllipsisExpr() ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) } - // NOTE can be a type + if tok := p.consume(token.Ellipsis); tok != nil { + var y ast.Node + + if p.match(simpleExprStartKinds...) { + if y = p.parseSimpleExpr(false); y == nil { + return nil + } + } + + return &ast.Op{ + X: nil, + Y: y, + Start: tok.Start, + End: tok.End, + Kind: ast.OperatorEllipsis, + } + } + + return p.parseSimpleExpr(false) +} + +func (p *parser) parseFunction(params *ast.ParenList) ast.Node { + if p.flags&Trace != 0 { + defer un(trace(p)) + } var result, body ast.Node if p.consume(token.Arrow) != nil { - // (...) -> T {} - result = p.parseType() + // (...) -> T + // (...) -> T {...} + result = p.parseSimpleExpr(false) if result == nil { return nil } - if !slices.Contains(endOfExprKinds, p.tok.Kind) { + if p.match(token.LCurly) { if block := p.parseBlock(); block != nil { body = block } } - } else { + } else if p.match(exprStartKinds...) { // (...) expr - if !slices.Contains(endOfExprKinds, p.tok.Kind) { - if expr := p.parseExpr(); expr != nil { - body = expr - } + if expr := p.parseExpr(); expr != nil { + body = expr } } if body == nil { + if result == nil { + return nil + } + return &ast.Signature{ Params: params, Result: result, @@ -617,7 +559,7 @@ func (p *parser) parseDeclNode(mut token.Pos, name *ast.Ident) *ast.Decl { switch { case p.tok.Kind != token.Colon && p.tok.Kind != token.Eq: - ty = p.parseType() + ty = p.parseEllipsisExpr() if ty == nil { return nil } @@ -647,7 +589,7 @@ func (p *parser) parseDeclNode(mut token.Pos, name *ast.Ident) *ast.Decl { } //------------------------------------------------ -// IDK +// Language constructions //------------------------------------------------ func (p *parser) parseAttributeListNode() *ast.AttributeList { @@ -669,83 +611,6 @@ func (p *parser) parseAttributeListNode() *ast.AttributeList { return nil } -func (p *parser) parseType() ast.Node { - if p.flags&Trace != 0 { - defer un(trace(p)) - } - - switch p.tok.Kind { - case token.Ellipsis: - // TODO allow only 1 variadic - - elipsis := p.consume() - op := &ast.Op{ - X: nil, - Y: nil, - Start: elipsis.Start, - End: elipsis.End, - Kind: ast.OperatorEllipsis, - } - - typeStart := p.save() - - if x := p.parseType(); x != nil { - op.X = x - return op - } - - if p.lastErrorIs(ErrorExpectedType) { - p.restore(typeStart) - } - - return op - - case token.Asterisk: - star := p.consume() - - return &ast.Op{ - X: nil, - Y: p.parseType(), - Start: star.Start, - End: star.End, - Kind: ast.OperatorPtr, - } - - case token.LBracket: - brackets := p.parseBracketList(p.parseExpr) - - return &ast.ArrayType{ - X: p.parseType(), - Args: brackets, - } - - case token.LParen: - params := p.parseParenList(p.declOr(p.parseType)) - if p.consume(token.Arrow) != nil { - return &ast.Signature{ - Params: params, - Result: p.parseType(), - } - } - return params - - case token.Ident: - return p.parseTypeName() - - case token.KwStruct: - return p.parseStructType() - - case token.KwEnum: - return p.parseEnumType() - - case token.Dollar: - return p.parseBuiltIn() - } - - p.error(ErrorExpectedType) - return nil -} - func (p *parser) parseStructType() ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) @@ -806,33 +671,6 @@ func (p *parser) parseEnumType() ast.Node { } } -func (p *parser) parseElse() ast.Node { - if p.flags&Trace != 0 { - defer un(trace(p)) - } - - if elseTok := p.consume(token.KwElse); elseTok != nil { - body := ast.Node(nil) - - if p.tok.Kind == token.KwIf { - body = p.parseIf() - } else if block := p.parseBlock(); block != nil { - body = block - } else { - start, end := p.skip() - p.errorAt(ErrorExpectedBlockOrIf, start, end) - return nil - } - - return &ast.Else{ - TokPos: elseTok.Start, - Body: body, - } - } - - return (*ast.Else)(nil) -} - func (p *parser) parseIf() ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) @@ -844,7 +682,7 @@ func (p *parser) parseIf() ast.Node { return nil } - cond := p.parseSimpleExpr() + cond := p.parseSimpleExpr(false) if cond == nil { start, end := p.skip() @@ -872,6 +710,33 @@ func (p *parser) parseIf() ast.Node { } } +func (p *parser) parseElse() ast.Node { + if p.flags&Trace != 0 { + defer un(trace(p)) + } + + if elseTok := p.consume(token.KwElse); elseTok != nil { + body := ast.Node(nil) + + if p.tok.Kind == token.KwIf { + body = p.parseIf() + } else if block := p.parseBlock(); block != nil { + body = block + } else { + start, end := p.skip() + p.errorAt(ErrorExpectedBlockOrIf, start, end) + return nil + } + + return &ast.Else{ + TokPos: elseTok.Start, + Body: body, + } + } + + return (*ast.Else)(nil) +} + func (p *parser) parseWhile() ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) @@ -882,7 +747,7 @@ func (p *parser) parseWhile() ast.Node { return nil } - cond := p.parseExpr() + cond := p.parseSimpleExpr(false) if cond == nil { return nil } @@ -918,7 +783,7 @@ func (p *parser) parseFor() ast.Node { return nil } - iterExpr := p.parseExpr() + iterExpr := p.parseSimpleExpr(false) if iterExpr == nil { return nil } @@ -991,7 +856,7 @@ func (p *parser) parseForLoopDecl() ast.Node { var ty ast.Node if p.consume(token.Colon) != nil { - ty = p.parseType() + ty = p.parseExpr() if ty == nil { return nil } @@ -1005,49 +870,75 @@ func (p *parser) parseForLoopDecl() ast.Node { } } +func (p *parser) parseDefer() ast.Node { + if p.flags&Trace != 0 { + defer un(trace(p)) + } + + tok := p.expect(token.KwDefer) + if tok == nil { + return nil + } + + x := p.parseExpr() + if x == nil { + return nil + } + + return &ast.Defer{X: x, TokPos: tok.Start} +} + func (p *parser) parseReturn() ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) } tok := p.expect(token.KwReturn) - x := p.parseExpr() + if tok == nil { + return nil + } - return &ast.Return{ - X: x, - TokPos: tok.Start, + var x ast.Node + + if !p.match(append(endOfStmtKinds, token.EOF)...) { + x = p.parseExpr() + if x == nil { + return nil + } } + + return &ast.Return{X: x, TokPos: tok.Start} } -func (p *parser) parseBreakOrContinue() ast.Node { +func (p *parser) parseBreak() ast.Node { if p.flags&Trace != 0 { defer un(trace(p)) } - // TODO implement new label syntax `break@label` - - tok := p.expect(token.KwBreak, token.KwContinue) - label := (*ast.Ident)(nil) + tok := p.expect(token.KwBreak) + if tok == nil { + return nil + } - if p.tok.Kind == token.Ident { - label = p.parseIdentNode() + return &ast.Break{ + Label: p.parseIdentNode(), + TokPos: tok.Start, } +} - switch tok.Kind { - case token.KwBreak: - return &ast.Break{ - Label: label, - TokPos: tok.Start, - } +func (p *parser) parseContinue() ast.Node { + if p.flags&Trace != 0 { + defer un(trace(p)) + } - case token.KwContinue: - return &ast.Continue{ - Label: label, - TokPos: tok.Start, - } + tok := p.expect(token.KwContinue) + if tok == nil { + return nil + } - default: - panic("unreachable") + return &ast.Continue{ + Label: p.parseIdentNode(), + TokPos: tok.Start, } } diff --git a/parser/parse_ast_util.go b/parser/parse_ast_util.go index a47add6..f840312 100644 --- a/parser/parse_ast_util.go +++ b/parser/parse_ast_util.go @@ -1,6 +1,8 @@ package parser import ( + "slices" + "github.com/saffage/jet/ast" "github.com/saffage/jet/token" ) @@ -54,77 +56,100 @@ func (p *parser) parseLiteralNode() *ast.Literal { return nil } -func (p *parser) parseDeclName() (mut token.Pos, name *ast.Ident) { - if p.flags&Trace != 0 { - defer un(trace(p)) +func (p *parser) skip(to ...token.Kind) (start, end token.Pos) { + if len(to) == 0 { + to = endOfExprKinds } - if tokMut := p.consume(token.KwMut); tokMut != nil { - mut = tokMut.Start - } + start = p.tok.Start - if ident := p.parseIdentNode(); ident != nil { - return mut, ident + for p.tok.Kind != token.EOF && !slices.Contains(to, p.tok.Kind) { + end = p.tok.End + p.next() } - if mut.IsValid() { - p.error(ErrorExpectedIdentAfterMut) - } else { - p.errorExpectedToken(token.Ident) + if p.flags&Trace != 0 && end.IsValid() { + // TODO must be removed + warn := Error{ + Start: start, + End: end, + Message: "tokens was skipped for some reason", + isWarn: true, + isInternal: true, + } + p.errors = append(p.errors, warn) } - return token.Pos{}, nil + return } -func (p *parser) parseTypeName() ast.Node { - if p.flags&Trace != 0 { - defer un(trace(p)) - } - - ident := p.parseIdentNode() - if ident == nil { - p.error(ErrorExpectedTypeName) - return nil - } - - path := p.parseDot(ident) - if path == nil { - return nil - } - - if p.tok.Kind == token.LBracket { - brackets := p.parseBracketList(p.parseExpr) - if brackets == nil { - return nil - } - - return &ast.Index{ - X: path, - Args: brackets, - } +var ( + endOfStmtKinds = []token.Kind{ + token.Semicolon, + token.NewLine, } - return path -} - -func (p *parser) isExprStart(kind token.Kind) bool { - switch kind { - case token.Ident, - token.Dollar, + endOfExprKinds = append(endOfStmtKinds, []token.Kind{ + token.Comma, + token.RParen, + token.RCurly, + token.RBracket, + }...) + + simpleExprStartKinds = []token.Kind{ + token.Minus, + token.Bang, + token.Asterisk, + token.Amp, + token.Ident, token.Int, token.Float, token.String, - token.LParen, - token.LCurly, - token.KwStruct, + token.Dollar, token.KwIf, token.KwWhile, + token.KwFor, + token.KwStruct, + token.KwEnum, + token.LCurly, + token.LBracket, + token.LParen, + } + + exprStartKinds = append(simpleExprStartKinds, []token.Kind{ + token.KwDefer, token.KwReturn, token.KwBreak, - token.KwContinue: - return true - - default: - return false + token.KwContinue, + }...) + + operators = map[token.Kind]ast.OperatorKind{ + token.Plus: ast.OperatorAdd, + token.Minus: ast.OperatorSub, + token.Asterisk: ast.OperatorMul, + token.Slash: ast.OperatorDiv, + token.Percent: ast.OperatorMod, + token.Eq: ast.OperatorAssign, + token.PlusEq: ast.OperatorAddAssign, + token.MinusEq: ast.OperatorSubAssign, + token.AsteriskEq: ast.OperatorMultAssign, + token.SlashEq: ast.OperatorDivAssign, + token.PercentEq: ast.OperatorModAssign, + token.EqOp: ast.OperatorEq, + token.NeOp: ast.OperatorNe, + token.LtOp: ast.OperatorLt, + token.LeOp: ast.OperatorLe, + token.GtOp: ast.OperatorGt, + token.GeOp: ast.OperatorGe, + token.Amp: ast.OperatorBitAnd, + token.Pipe: ast.OperatorBitOr, + token.Caret: ast.OperatorBitXor, + token.Shl: ast.OperatorBitShl, + token.Shr: ast.OperatorBitShr, + token.KwAnd: ast.OperatorAnd, + token.KwOr: ast.OperatorOr, + token.KwAs: ast.OperatorAs, + token.Dot2: ast.OperatorRangeInclusive, + token.Dot2Less: ast.OperatorRangeExclusive, } -} +) diff --git a/scanner/scanner.go b/scanner/scanner.go index 503b212..e6ad65e 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -115,7 +115,7 @@ func (s *Scanner) Next() token.Token { tok = token.Token{Kind: kind} - case s.Consume('!', '+', '*', '/', '%'): + case s.Consume('!', '+', '*', '/', '%', '&', '|', '^'): // NOTE This tokens is order dependent kind := token.KindFromString(string(s.Prev())) @@ -169,7 +169,7 @@ func (s *Scanner) Next() token.Token { tok = token.Token{Kind: kind} - case s.Match('?', '&', '|', '^', ',', ':', ';', '(', ')', '[', ']', '{', '}'): + case s.Match('?', ',', ':', ';', '(', ')', '[', ']', '{', '}'): kind := token.KindFromString(string(s.Advance())) if kind == token.Illegal { diff --git a/token/kind.go b/token/kind.go index d264969..41e3504 100644 --- a/token/kind.go +++ b/token/kind.go @@ -46,6 +46,10 @@ const ( LeOp // operator '<=' GtOp // operator '>' GeOp // operator '>=' + Shl // operator '<<' + ShlEq // operator '<<=' + Shr // operator '>>' + ShrEq // operator '>>=' Plus // operator '+' PlusEq // operator '+=' Minus // operator '-' @@ -56,19 +60,20 @@ const ( SlashEq // operator '/=' Percent // operator '%' PercentEq // operator '%=' + Amp // operator '&' + AmpEq // operator '&=' + Pipe // operator '|' + PipeEq // operator '|=' + Caret // operator '^' + CaretEq // operator '^=' // End of position dependent tokens. - Amp // operator '&' - Pipe // operator '|' - Caret // operator '^' At // operator '@' Dollar // operator '$' QuestionMark // operator '?' Arrow // operator '->' FatArrow // operator '=>' - Shl // operator '<<' - Shr // operator '>>' Dot // operator '.' Dot2 // operator '..' Dot2Less // operator '..<' @@ -85,6 +90,7 @@ const ( KwFor // keyword 'for' KwIn // keyword 'in' KwAs // keyword 'as' + KwDefer // keyword 'defer' KwReturn // keyword 'return' KwBreak // keyword 'break' KwContinue // keyword 'continue' @@ -207,15 +213,20 @@ var representableKinds = map[Kind]string{ Arrow: "->", FatArrow: "=>", Shl: "<<", + ShlEq: "<<=", Shr: ">>", + ShrEq: ">>=", Plus: "+", Minus: "-", Asterisk: "*", Slash: "/", Percent: "%", Amp: "&", + AmpEq: "&=", Pipe: "|", + PipeEq: "|=", Caret: "^", + CaretEq: "^=", At: "@", Dollar: "$", PlusEq: "+=", @@ -237,6 +248,7 @@ var representableKinds = map[Kind]string{ KwFor: "for", KwIn: "in", KwAs: "as", + KwDefer: "defer", KwReturn: "return", KwBreak: "break", KwContinue: "continue", diff --git a/token/kind_string.go b/token/kind_string.go index f789008..4a68d9f 100644 --- a/token/kind_string.go +++ b/token/kind_string.go @@ -35,49 +35,55 @@ func _() { _ = x[LeOp-24] _ = x[GtOp-25] _ = x[GeOp-26] - _ = x[Plus-27] - _ = x[PlusEq-28] - _ = x[Minus-29] - _ = x[MinusEq-30] - _ = x[Asterisk-31] - _ = x[AsteriskEq-32] - _ = x[Slash-33] - _ = x[SlashEq-34] - _ = x[Percent-35] - _ = x[PercentEq-36] - _ = x[Amp-37] - _ = x[Pipe-38] - _ = x[Caret-39] - _ = x[At-40] - _ = x[Dollar-41] - _ = x[QuestionMark-42] - _ = x[Arrow-43] - _ = x[FatArrow-44] - _ = x[Shl-45] - _ = x[Shr-46] - _ = x[Dot-47] - _ = x[Dot2-48] - _ = x[Dot2Less-49] - _ = x[Ellipsis-50] - _ = x[KwAnd-51] - _ = x[KwOr-52] - _ = x[KwStruct-53] - _ = x[KwEnum-54] - _ = x[KwMut-55] - _ = x[KwIf-56] - _ = x[KwElse-57] - _ = x[KwWhile-58] - _ = x[KwFor-59] - _ = x[KwIn-60] - _ = x[KwAs-61] - _ = x[KwReturn-62] - _ = x[KwBreak-63] - _ = x[KwContinue-64] + _ = x[Shl-27] + _ = x[ShlEq-28] + _ = x[Shr-29] + _ = x[ShrEq-30] + _ = x[Plus-31] + _ = x[PlusEq-32] + _ = x[Minus-33] + _ = x[MinusEq-34] + _ = x[Asterisk-35] + _ = x[AsteriskEq-36] + _ = x[Slash-37] + _ = x[SlashEq-38] + _ = x[Percent-39] + _ = x[PercentEq-40] + _ = x[Amp-41] + _ = x[AmpEq-42] + _ = x[Pipe-43] + _ = x[PipeEq-44] + _ = x[Caret-45] + _ = x[CaretEq-46] + _ = x[At-47] + _ = x[Dollar-48] + _ = x[QuestionMark-49] + _ = x[Arrow-50] + _ = x[FatArrow-51] + _ = x[Dot-52] + _ = x[Dot2-53] + _ = x[Dot2Less-54] + _ = x[Ellipsis-55] + _ = x[KwAnd-56] + _ = x[KwOr-57] + _ = x[KwStruct-58] + _ = x[KwEnum-59] + _ = x[KwMut-60] + _ = x[KwIf-61] + _ = x[KwElse-62] + _ = x[KwWhile-63] + _ = x[KwFor-64] + _ = x[KwIn-65] + _ = x[KwAs-66] + _ = x[KwDefer-67] + _ = x[KwReturn-68] + _ = x[KwBreak-69] + _ = x[KwContinue-70] } -const _Kind_name = "IllegalEOFCommentWhitespaceTabNewLineIdentIntFloatStringLParenRParenLCurlyRCurlyLBracketRBracketCommaColonSemicolonEqEqOpBangNeOpLtOpLeOpGtOpGeOpPlusPlusEqMinusMinusEqAsteriskAsteriskEqSlashSlashEqPercentPercentEqAmpPipeCaretAtDollarQuestionMarkArrowFatArrowShlShrDotDot2Dot2LessEllipsisKwAndKwOrKwStructKwEnumKwMutKwIfKwElseKwWhileKwForKwInKwAsKwReturnKwBreakKwContinue" +const _Kind_name = "IllegalEOFCommentWhitespaceTabNewLineIdentIntFloatStringLParenRParenLCurlyRCurlyLBracketRBracketCommaColonSemicolonEqEqOpBangNeOpLtOpLeOpGtOpGeOpShlShlEqShrShrEqPlusPlusEqMinusMinusEqAsteriskAsteriskEqSlashSlashEqPercentPercentEqAmpAmpEqPipePipeEqCaretCaretEqAtDollarQuestionMarkArrowFatArrowDotDot2Dot2LessEllipsisKwAndKwOrKwStructKwEnumKwMutKwIfKwElseKwWhileKwForKwInKwAsKwDeferKwReturnKwBreakKwContinue" -var _Kind_index = [...]uint16{0, 7, 10, 17, 27, 30, 37, 42, 45, 50, 56, 62, 68, 74, 80, 88, 96, 101, 106, 115, 117, 121, 125, 129, 133, 137, 141, 145, 149, 155, 160, 167, 175, 185, 190, 197, 204, 213, 216, 220, 225, 227, 233, 245, 250, 258, 261, 264, 267, 271, 279, 287, 292, 296, 304, 310, 315, 319, 325, 332, 337, 341, 345, 353, 360, 370} +var _Kind_index = [...]uint16{0, 7, 10, 17, 27, 30, 37, 42, 45, 50, 56, 62, 68, 74, 80, 88, 96, 101, 106, 115, 117, 121, 125, 129, 133, 137, 141, 145, 148, 153, 156, 161, 165, 171, 176, 183, 191, 201, 206, 213, 220, 229, 232, 237, 241, 247, 252, 259, 261, 267, 279, 284, 292, 295, 299, 307, 315, 320, 324, 332, 338, 343, 347, 353, 360, 365, 369, 373, 380, 388, 395, 405} func (i Kind) String() string { if i >= Kind(len(_Kind_index)-1) { diff --git a/token/kind_user_string.go b/token/kind_user_string.go index 08a1101..ea8be66 100644 --- a/token/kind_user_string.go +++ b/token/kind_user_string.go @@ -35,49 +35,55 @@ func _() { _ = x[LeOp-24] _ = x[GtOp-25] _ = x[GeOp-26] - _ = x[Plus-27] - _ = x[PlusEq-28] - _ = x[Minus-29] - _ = x[MinusEq-30] - _ = x[Asterisk-31] - _ = x[AsteriskEq-32] - _ = x[Slash-33] - _ = x[SlashEq-34] - _ = x[Percent-35] - _ = x[PercentEq-36] - _ = x[Amp-37] - _ = x[Pipe-38] - _ = x[Caret-39] - _ = x[At-40] - _ = x[Dollar-41] - _ = x[QuestionMark-42] - _ = x[Arrow-43] - _ = x[FatArrow-44] - _ = x[Shl-45] - _ = x[Shr-46] - _ = x[Dot-47] - _ = x[Dot2-48] - _ = x[Dot2Less-49] - _ = x[Ellipsis-50] - _ = x[KwAnd-51] - _ = x[KwOr-52] - _ = x[KwStruct-53] - _ = x[KwEnum-54] - _ = x[KwMut-55] - _ = x[KwIf-56] - _ = x[KwElse-57] - _ = x[KwWhile-58] - _ = x[KwFor-59] - _ = x[KwIn-60] - _ = x[KwAs-61] - _ = x[KwReturn-62] - _ = x[KwBreak-63] - _ = x[KwContinue-64] + _ = x[Shl-27] + _ = x[ShlEq-28] + _ = x[Shr-29] + _ = x[ShrEq-30] + _ = x[Plus-31] + _ = x[PlusEq-32] + _ = x[Minus-33] + _ = x[MinusEq-34] + _ = x[Asterisk-35] + _ = x[AsteriskEq-36] + _ = x[Slash-37] + _ = x[SlashEq-38] + _ = x[Percent-39] + _ = x[PercentEq-40] + _ = x[Amp-41] + _ = x[AmpEq-42] + _ = x[Pipe-43] + _ = x[PipeEq-44] + _ = x[Caret-45] + _ = x[CaretEq-46] + _ = x[At-47] + _ = x[Dollar-48] + _ = x[QuestionMark-49] + _ = x[Arrow-50] + _ = x[FatArrow-51] + _ = x[Dot-52] + _ = x[Dot2-53] + _ = x[Dot2Less-54] + _ = x[Ellipsis-55] + _ = x[KwAnd-56] + _ = x[KwOr-57] + _ = x[KwStruct-58] + _ = x[KwEnum-59] + _ = x[KwMut-60] + _ = x[KwIf-61] + _ = x[KwElse-62] + _ = x[KwWhile-63] + _ = x[KwFor-64] + _ = x[KwIn-65] + _ = x[KwAs-66] + _ = x[KwDefer-67] + _ = x[KwReturn-68] + _ = x[KwBreak-69] + _ = x[KwContinue-70] } -const _Kind_user_name = "illegal characterend of filecommentwhitespacehorizontal tabulationnew lineidentifieruntyped intuntyped floatuntyped string'('')''{''}''['']'','':'';'operator '='operator '=='operator '!'operator '!='operator '<'operator '<='operator '>'operator '>='operator '+'operator '+='operator '-'operator '-='operator '*'operator '*='operator '/'operator '/='operator '%'operator '%='operator '&'operator '|'operator '^'operator '@'operator '$'operator '?'operator '->'operator '=>'operator '<<'operator '>>'operator '.'operator '..'operator '..<'operator '...'keyword 'and'keyword 'or'keyword 'struct'keyword 'enum'keyword 'mut'keyword 'if'keyword 'else'keyword 'while'keyword 'for'keyword 'in'keyword 'as'keyword 'return'keyword 'break'keyword 'continue'" +const _Kind_user_name = "illegal characterend of filecommentwhitespacehorizontal tabulationnew lineidentifieruntyped intuntyped floatuntyped string'('')''{''}''['']'','':'';'operator '='operator '=='operator '!'operator '!='operator '<'operator '<='operator '>'operator '>='operator '<<'operator '<<='operator '>>'operator '>>='operator '+'operator '+='operator '-'operator '-='operator '*'operator '*='operator '/'operator '/='operator '%'operator '%='operator '&'operator '&='operator '|'operator '|='operator '^'operator '^='operator '@'operator '$'operator '?'operator '->'operator '=>'operator '.'operator '..'operator '..<'operator '...'keyword 'and'keyword 'or'keyword 'struct'keyword 'enum'keyword 'mut'keyword 'if'keyword 'else'keyword 'while'keyword 'for'keyword 'in'keyword 'as'keyword 'defer'keyword 'return'keyword 'break'keyword 'continue'" -var _Kind_user_index = [...]uint16{0, 17, 28, 35, 45, 66, 74, 84, 95, 108, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 161, 174, 186, 199, 211, 224, 236, 249, 261, 274, 286, 299, 311, 324, 336, 349, 361, 374, 386, 398, 410, 422, 434, 446, 459, 472, 485, 498, 510, 523, 537, 551, 564, 576, 592, 606, 619, 631, 645, 660, 673, 685, 697, 713, 728, 746} +var _Kind_user_index = [...]uint16{0, 17, 28, 35, 45, 66, 74, 84, 95, 108, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 161, 174, 186, 199, 211, 224, 236, 249, 262, 276, 289, 303, 315, 328, 340, 353, 365, 378, 390, 403, 415, 428, 440, 453, 465, 478, 490, 503, 515, 527, 539, 552, 565, 577, 590, 604, 618, 631, 643, 659, 673, 686, 698, 712, 727, 740, 752, 764, 779, 795, 810, 828} func (i Kind) UserString() string { if i >= Kind(len(_Kind_user_index)-1) { diff --git a/token/token.go b/token/token.go index b277f26..8514c2a 100644 --- a/token/token.go +++ b/token/token.go @@ -77,7 +77,7 @@ func (t Token) Precedence() int { case KwAs: return 2 - case Eq, PlusEq, MinusEq, AsteriskEq, SlashEq, PercentEq: + case Eq, PlusEq, MinusEq, AsteriskEq, SlashEq, PercentEq, AmpEq, PipeEq, CaretEq, ShlEq, ShrEq: return 1 default: