Skip to content

Commit

Permalink
feat, refactor: replace postfix ! operator with prefix *, move op…
Browse files Browse the repository at this point in the history
…erator checking into a separate file
  • Loading branch information
saffage committed May 8, 2024
1 parent f31a96b commit 8d2b153
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 169 deletions.
5 changes: 3 additions & 2 deletions ast/operator_kind.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
OperatorNeg // -
OperatorAddr // &
OperatorMutAddr // &var
OperatorDeref // *

// Infix.

Expand All @@ -39,8 +40,8 @@ const (

// Postfix.

OperatorTry // ?
OperatorUnwrap // !
// OperatorTry // ?
// OperatorUnwrap // !
)

func (kind OperatorKind) MarshalJSON() ([]byte, error) {
Expand Down
45 changes: 22 additions & 23 deletions ast/operator_kind_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 128 additions & 0 deletions checker/operators.go
Original file line number Diff line number Diff line change
@@ -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
}
116 changes: 4 additions & 112 deletions checker/type_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
Loading

0 comments on commit 8d2b153

Please sign in to comment.