From 8d2b15397176daef42f8d15409a589276536d49d Mon Sep 17 00:00:00 2001 From: Saffage <04coder@gmail.com> Date: Wed, 8 May 2024 16:08:11 +0300 Subject: [PATCH] feat, refactor: replace postfix `!` operator with prefix `*`, move operator checking into a separate file --- ast/operator_kind.go | 5 +- ast/operator_kind_string.go | 45 +++++++------ checker/operators.go | 128 ++++++++++++++++++++++++++++++++++++ checker/type_resolver.go | 116 ++------------------------------ parser/parse_ast.go | 76 ++++++++++++--------- 5 files changed, 201 insertions(+), 169 deletions(-) create mode 100644 checker/operators.go diff --git a/ast/operator_kind.go b/ast/operator_kind.go index a3f5dac..8965faf 100644 --- a/ast/operator_kind.go +++ b/ast/operator_kind.go @@ -14,6 +14,7 @@ const ( OperatorNeg // - OperatorAddr // & OperatorMutAddr // &var + OperatorDeref // * // Infix. @@ -39,8 +40,8 @@ const ( // Postfix. - OperatorTry // ? - OperatorUnwrap // ! + // OperatorTry // ? + // OperatorUnwrap // ! ) func (kind OperatorKind) MarshalJSON() ([]byte, error) { diff --git a/ast/operator_kind_string.go b/ast/operator_kind_string.go index bdc6ec4..15fd64d 100644 --- a/ast/operator_kind_string.go +++ b/ast/operator_kind_string.go @@ -13,32 +13,31 @@ func _() { _ = x[OperatorNeg-2] _ = x[OperatorAddr-3] _ = x[OperatorMutAddr-4] - _ = x[OperatorAssign-5] - _ = x[OperatorAdd-6] - _ = x[OperatorSub-7] - _ = x[OperatorMul-8] - _ = x[OperatorDiv-9] - _ = x[OperatorMod-10] - _ = x[OperatorEq-11] - _ = x[OperatorNe-12] - _ = x[OperatorLt-13] - _ = x[OperatorLe-14] - _ = x[OperatorGt-15] - _ = x[OperatorGe-16] - _ = x[OperatorBitAnd-17] - _ = x[OperatorBitOr-18] - _ = x[OperatorBitXor-19] - _ = x[OperatorBitShl-20] - _ = x[OperatorBitShr-21] - _ = x[OperatorAnd-22] - _ = x[OperatorOr-23] - _ = x[OperatorTry-24] - _ = x[OperatorUnwrap-25] + _ = x[OperatorDeref-5] + _ = x[OperatorAssign-6] + _ = x[OperatorAdd-7] + _ = x[OperatorSub-8] + _ = x[OperatorMul-9] + _ = x[OperatorDiv-10] + _ = x[OperatorMod-11] + _ = x[OperatorEq-12] + _ = x[OperatorNe-13] + _ = x[OperatorLt-14] + _ = x[OperatorLe-15] + _ = x[OperatorGt-16] + _ = x[OperatorGe-17] + _ = x[OperatorBitAnd-18] + _ = x[OperatorBitOr-19] + _ = x[OperatorBitXor-20] + _ = x[OperatorBitShl-21] + _ = x[OperatorBitShr-22] + _ = x[OperatorAnd-23] + _ = x[OperatorOr-24] } -const _OperatorKind_name = "UnknownOperator!-&&var=+-*/%==!=<<=>>=&|^<<>>andor?!" +const _OperatorKind_name = "UnknownOperator!-&&var*=+-*/%==!=<<=>>=&|^<<>>andor" -var _OperatorKind_index = [...]uint8{0, 15, 16, 17, 18, 22, 23, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36, 38, 39, 40, 41, 43, 45, 48, 50, 51, 52} +var _OperatorKind_index = [...]uint8{0, 15, 16, 17, 18, 22, 23, 24, 25, 26, 27, 28, 29, 31, 33, 34, 36, 37, 39, 40, 41, 42, 44, 46, 49, 51} func (i OperatorKind) String() string { if i >= OperatorKind(len(_OperatorKind_index)-1) { diff --git a/checker/operators.go b/checker/operators.go new file mode 100644 index 0000000..722685e --- /dev/null +++ b/checker/operators.go @@ -0,0 +1,128 @@ +package checker + +import ( + "fmt" + + "github.com/saffage/jet/ast" + "github.com/saffage/jet/types" +) + +func (check *Checker) prefix(node *ast.PrefixOp, tOperand types.Type) types.Type { + switch node.Opr.Kind { + case ast.OperatorNeg: + if p := types.AsPrimitive(tOperand); p != nil { + switch p.Kind() { + case types.UntypedInt, types.UntypedFloat, types.I32: + return tOperand + } + } + + case ast.OperatorNot: + if p := types.AsPrimitive(tOperand); p != nil { + switch p.Kind() { + case types.UntypedBool, types.Bool: + return tOperand + } + } + + case ast.OperatorDeref: + if ref := types.AsRef(tOperand); ref != nil { + return ref.Base() + } + + check.errorf(node.X, "expression is not a reference type") + return nil + + case ast.OperatorAddr: + if types.IsTypeDesc(tOperand) { + t := types.NewRef(types.SkipTypeDesc(tOperand)) + return types.NewTypeDesc(t) + } + + return types.NewRef(types.SkipUntyped(tOperand)) + + case ast.OperatorMutAddr: + panic("not implemented") + + default: + panic(fmt.Sprintf("unknown prefix operator: '%s'", node.Opr.Kind)) + } + + check.errorf( + node.Opr, + "operator '%s' is not defined for the type (%s)", + node.Opr.Kind, + tOperand, + ) + return nil +} + +func (check *Checker) infix(node *ast.InfixOp, tOperandX, tOperandY types.Type) types.Type { + if !tOperandX.Equals(tOperandY) { + check.errorf(node, "type mismatch (%s and %s)", tOperandX, tOperandY) + return nil + } + + // Assignment operation doesn't have a value. + if node.Opr.Kind == ast.OperatorAssign { + return types.Unit + } + + primitive := types.AsPrimitive(tOperandX) + + if primitive == nil { + check.errorf(node, "only primitive types have operators") + return nil + } + + switch node.Opr.Kind { + case ast.OperatorAdd, + ast.OperatorSub, + ast.OperatorMul, + ast.OperatorDiv, + ast.OperatorMod, + ast.OperatorBitAnd, + ast.OperatorBitOr, + ast.OperatorBitXor, + ast.OperatorBitShl, + ast.OperatorBitShr: + switch primitive.Kind() { + case types.UntypedInt, types.UntypedFloat, types.I32: + return tOperandX + } + + case ast.OperatorEq, + ast.OperatorNe, + ast.OperatorLt, + ast.OperatorLe, + ast.OperatorGt, + ast.OperatorGe: + switch primitive.Kind() { + case types.UntypedBool, types.UntypedInt, types.UntypedFloat: + return types.Primitives[types.UntypedBool] + + case types.Bool, types.I32: + return types.Primitives[types.Bool] + } + + case ast.OperatorAnd, ast.OperatorOr: + switch primitive.Kind() { + case types.UntypedBool: + return types.Primitives[types.UntypedBool] + + case types.Bool: + return types.Primitives[types.Bool] + } + + default: + panic(fmt.Sprintf("unknown infix operator: '%s'", node.Opr.Kind)) + } + + check.errorf( + node.Opr, + "operator '%s' is not defined for the type (%s)", + node.Opr.Kind, + tOperandX, + ) + return nil +} diff --git a/checker/type_resolver.go b/checker/type_resolver.go index 2fe5d87..47806cd 100644 --- a/checker/type_resolver.go +++ b/checker/type_resolver.go @@ -329,51 +329,7 @@ func (check *Checker) typeOfPrefixOp(node *ast.PrefixOp) types.Type { return nil } - switch node.Opr.Kind { - case ast.OperatorNeg: - if p := types.AsPrimitive(tOperand); p != nil { - switch p.Kind() { - case types.UntypedInt, types.UntypedFloat, types.I32: - return tOperand - } - } - - check.errorf( - node.Opr, - "operator '%s' is not defined for the type (%s)", - node.Opr.Kind.String(), - tOperand.String()) - return nil - - case ast.OperatorNot: - if p, ok := tOperand.Underlying().(*types.Primitive); ok { - switch p.Kind() { - case types.UntypedBool, types.Bool: - return tOperand - } - } - - check.errorf( - node.X, - "operator '%s' is not defined for the type (%s)", - node.Opr.Kind.String(), - tOperand.String()) - return nil - - case ast.OperatorAddr: - if types.IsTypeDesc(tOperand) { - t := types.NewRef(types.SkipTypeDesc(tOperand)) - return types.NewTypeDesc(t) - } - - return types.NewRef(types.SkipUntyped(tOperand)) - - case ast.OperatorMutAddr: - panic("not implemented") - - default: - panic("unreachable") - } + return check.prefix(node, tOperand) } func (check *Checker) typeOfInfixOp(node *ast.InfixOp) types.Type { @@ -387,76 +343,12 @@ func (check *Checker) typeOfInfixOp(node *ast.InfixOp) types.Type { return nil } - if !tOperandX.Equals(tOperandY) { - check.errorf(node, "type mismatch (%s and %s)", tOperandX, tOperandY) - return nil - } - - if node.Opr.Kind == ast.OperatorAssign { - return types.Unit - } - - if primitive := types.AsPrimitive(tOperandX); primitive != nil { - switch node.Opr.Kind { - case ast.OperatorAdd, ast.OperatorSub, ast.OperatorMul, ast.OperatorDiv, ast.OperatorMod, - ast.OperatorBitAnd, ast.OperatorBitOr, ast.OperatorBitXor, ast.OperatorBitShl, ast.OperatorBitShr: - switch primitive.Kind() { - case types.UntypedInt, types.UntypedFloat, types.I32: - return tOperandX - } - - case ast.OperatorEq, ast.OperatorNe, ast.OperatorLt, ast.OperatorLe, ast.OperatorGt, ast.OperatorGe: - switch primitive.Kind() { - case types.UntypedBool, types.UntypedInt, types.UntypedFloat: - return types.Primitives[types.UntypedBool] - - case types.Bool, types.I32: - return types.Primitives[types.Bool] - } - - case ast.OperatorAnd, ast.OperatorOr: - switch primitive.Kind() { - case types.UntypedBool: - return types.Primitives[types.UntypedBool] - - case types.Bool: - return types.Primitives[types.Bool] - } - - default: - panic("unreachable") - } - } - - check.errorf( - node.Opr, - "operator '%s' is not defined for the type '%s'", - node.Opr.Kind.String(), - tOperandX.String()) - return nil + return check.infix(node, tOperandX, tOperandY) } func (check *Checker) typeOfPostfixOp(node *ast.PostfixOp) types.Type { - tOperand := check.typeOf(node.X) - if tOperand == nil { - return nil - } - - switch node.Opr.Kind { - case ast.OperatorUnwrap: - if ref := types.AsRef(tOperand); ref != nil { - return ref.Base() - } - - check.errorf(node.X, "expression is not a reference type") - return nil - - case ast.OperatorTry: - panic("not inplemented") - - default: - panic("unreachable") - } + check.errorf(node, "postfix operators are not supported") + return nil } func (check *Checker) typeOfBracketList(node *ast.BracketList) types.Type { diff --git a/parser/parse_ast.go b/parser/parse_ast.go index 13c8253..e935c66 100644 --- a/parser/parse_ast.go +++ b/parser/parse_ast.go @@ -406,34 +406,34 @@ func (p *Parser) parseSuffixExpr(x ast.Node) ast.Node { case token.Dot: x = p.parseMemberAccess(x) - case token.QuestionMark, token.Bang: - opr := p.consume() - postfixOpKind := ast.UnknownOperator - - switch opr.Kind { - case token.QuestionMark: - postfixOpKind = ast.OperatorTry - - case token.Bang: - postfixOpKind = ast.OperatorUnwrap - - default: - p.errorf( - opr.Start, - opr.End, - "%s can't be used as postfix operator", - opr.Kind.UserString(), - ) - } - - x = &ast.PostfixOp{ - X: x, - Opr: &ast.Operator{ - Start: opr.Start, - End: opr.End, - Kind: postfixOpKind, - }, - } + // case token.QuestionMark, token.Bang: + // opr := p.consume() + // postfixOpKind := ast.UnknownOperator + // + // switch opr.Kind { + // case token.QuestionMark: + // postfixOpKind = ast.OperatorTry + // + // case token.Bang: + // postfixOpKind = ast.OperatorUnwrap + // + // default: + // p.errorf( + // opr.Start, + // opr.End, + // "%s can't be used as postfix operator", + // opr.Kind.UserString(), + // ) + // } + // + // x = &ast.PostfixOp{ + // X: x, + // Opr: &ast.Operator{ + // Start: opr.Start, + // End: opr.End, + // Kind: postfixOpKind, + // }, + // } case token.LBracket: x = &ast.Index{ @@ -778,13 +778,13 @@ func (p *Parser) parseType() ast.Node { switch p.tok.Kind { case token.Amp: - ampLoc := p.expect().Start + amp := p.consume() if varTok := p.consume(token.KwVar); varTok != nil { return &ast.PrefixOp{ X: p.parseType(), Opr: &ast.Operator{ - Start: ampLoc, + Start: amp.Start, End: varTok.End, Kind: ast.OperatorMutAddr, }, @@ -794,12 +794,24 @@ func (p *Parser) parseType() ast.Node { return &ast.PrefixOp{ X: p.parseType(), Opr: &ast.Operator{ - Start: ampLoc, - End: ampLoc, + Start: amp.Start, + End: amp.End, Kind: ast.OperatorAddr, }, } + case token.Asterisk: + asterisk := p.consume() + + return &ast.PrefixOp{ + X: p.parseType(), + Opr: &ast.Operator{ + Start: asterisk.Start, + End: asterisk.End, + Kind: ast.OperatorDeref, + }, + } + case token.LBracket: brackets := p.parseBracketList(p.parseExpr)