Rework analyzer code to fit new parser
This commit is contained in:
parent
090d52b8f8
commit
5bb9508a76
@ -2,8 +2,7 @@ package analyzer
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "math"
|
import "math"
|
||||||
import "github.com/alecthomas/participle/v2"
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||||
import "github.com/alecthomas/participle/v2/lexer"
|
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/integer"
|
import "git.tebibyte.media/sashakoshka/fspl/integer"
|
||||||
|
|
||||||
@ -24,7 +23,7 @@ type strictness int; const (
|
|||||||
// canAssign takes in an analyzed destination type and an analyzed source type,
|
// canAssign takes in an analyzed destination type and an analyzed source type,
|
||||||
// and determines whether source can be assigned to destination.
|
// and determines whether source can be assigned to destination.
|
||||||
func (this *Tree) canAssign (
|
func (this *Tree) canAssign (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
// assuming both are analyzed already
|
// assuming both are analyzed already
|
||||||
destination entity.Type,
|
destination entity.Type,
|
||||||
mode strictness,
|
mode strictness,
|
||||||
@ -33,13 +32,13 @@ func (this *Tree) canAssign (
|
|||||||
fail := func () error {
|
fail := func () error {
|
||||||
switch mode {
|
switch mode {
|
||||||
case strict:
|
case strict:
|
||||||
return participle.Errorf(pos, "expected %v", destination)
|
return errors.Errorf(pos, "expected %v", destination)
|
||||||
case weak:
|
case weak:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
pos, "cannot use %v as %v",
|
pos, "cannot use %v as %v",
|
||||||
source, destination)
|
source, destination)
|
||||||
case structural:
|
case structural:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
pos, "cannot convert from %v to %v",
|
pos, "cannot convert from %v to %v",
|
||||||
source, destination)
|
source, destination)
|
||||||
default:
|
default:
|
||||||
@ -142,12 +141,12 @@ func (this *Tree) canAssign (
|
|||||||
// canAssignCoerce determines if data of an analyzed source type can be
|
// canAssignCoerce determines if data of an analyzed source type can be
|
||||||
// converted into data of an analyzed destination type.
|
// converted into data of an analyzed destination type.
|
||||||
func (this *Tree) canAssignCoerce (
|
func (this *Tree) canAssignCoerce (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
destination entity.Type,
|
destination entity.Type,
|
||||||
source entity.Type,
|
source entity.Type,
|
||||||
) error {
|
) error {
|
||||||
fail := func () error {
|
fail := func () error {
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
pos, "cannot convert from %v to %v",
|
pos, "cannot convert from %v to %v",
|
||||||
source, destination)
|
source, destination)
|
||||||
}
|
}
|
||||||
@ -213,13 +212,13 @@ func (this *Tree) canAssignCoerce (
|
|||||||
// canAssignSliceArray takes in an analyzed slice type and an analyzed array
|
// canAssignSliceArray takes in an analyzed slice type and an analyzed array
|
||||||
// type, and determines whether the array can be assigned to the slice.
|
// type, and determines whether the array can be assigned to the slice.
|
||||||
func (this *Tree) canAssignSliceArray (
|
func (this *Tree) canAssignSliceArray (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
destination *entity.TypeSlice,
|
destination *entity.TypeSlice,
|
||||||
source *entity.TypeArray,
|
source *entity.TypeArray,
|
||||||
) error {
|
) error {
|
||||||
err := this.canAssign(pos, destination.Element, strict, source.Element)
|
err := this.canAssign(pos, destination.Element, strict, source.Element)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return participle.Errorf(pos, "expected %v", destination)
|
return errors.Errorf(pos, "expected %v", destination)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -229,7 +228,7 @@ func (this *Tree) canAssignSliceArray (
|
|||||||
// analyzed source type, and determines whether source can be assigned to
|
// analyzed source type, and determines whether source can be assigned to
|
||||||
// destination.
|
// destination.
|
||||||
func (this *Tree) canAssignInterface (
|
func (this *Tree) canAssignInterface (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
destination *entity.TypeInterface,
|
destination *entity.TypeInterface,
|
||||||
source entity.Type,
|
source entity.Type,
|
||||||
) error {
|
) error {
|
||||||
@ -254,7 +253,7 @@ func (this *Tree) canAssignInterface (
|
|||||||
|
|
||||||
// check equivalence
|
// check equivalence
|
||||||
if !signature.Equals(behavior) {
|
if !signature.Equals(behavior) {
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
pos, "%v has wrong signature for method %v",
|
pos, "%v has wrong signature for method %v",
|
||||||
source, name)
|
source, name)
|
||||||
}
|
}
|
||||||
@ -326,60 +325,60 @@ func (this *Tree) isLocationExpression (expression entity.Expression) error {
|
|||||||
case *entity.Declaration:
|
case *entity.Declaration:
|
||||||
return nil
|
return nil
|
||||||
case *entity.Call:
|
case *entity.Call:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to function call")
|
"cannot assign to function call")
|
||||||
case *entity.MethodCall:
|
case *entity.MethodCall:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to method call")
|
"cannot assign to method call")
|
||||||
case *entity.Subscript:
|
case *entity.Subscript:
|
||||||
return this.isLocationExpression(expression.Slice)
|
return this.isLocationExpression(expression.Slice)
|
||||||
case *entity.Slice:
|
case *entity.Slice:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to slice operation")
|
"cannot assign to slice operation")
|
||||||
case *entity.Dereference:
|
case *entity.Dereference:
|
||||||
return this.isLocationExpression(expression.Pointer)
|
return this.isLocationExpression(expression.Pointer)
|
||||||
case *entity.Reference:
|
case *entity.Reference:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to reference operation")
|
"cannot assign to reference operation")
|
||||||
case *entity.ValueCast:
|
case *entity.ValueCast:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to value cast")
|
"cannot assign to value cast")
|
||||||
case *entity.BitCast:
|
case *entity.BitCast:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to bit cast")
|
"cannot assign to bit cast")
|
||||||
case *entity.Operation:
|
case *entity.Operation:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to %v operation",
|
"cannot assign to %v operation",
|
||||||
expression.Operator)
|
expression.Operator)
|
||||||
case *entity.Block:
|
case *entity.Block:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to block")
|
"cannot assign to block")
|
||||||
case *entity.MemberAccess:
|
case *entity.MemberAccess:
|
||||||
return this.isLocationExpression (
|
return this.isLocationExpression (
|
||||||
expression.Source)
|
expression.Source)
|
||||||
case *entity.IfElse:
|
case *entity.IfElse:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to if/else")
|
"cannot assign to if/else")
|
||||||
case *entity.Loop:
|
case *entity.Loop:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to loop")
|
"cannot assign to loop")
|
||||||
case *entity.Break:
|
case *entity.Break:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to break statement")
|
"cannot assign to break statement")
|
||||||
case *entity.Return:
|
case *entity.Return:
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
expression.Pos,
|
expression.Position,
|
||||||
"cannot assign to return statement")
|
"cannot assign to return statement")
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprint (
|
panic(fmt.Sprint (
|
||||||
|
@ -12,6 +12,8 @@ func (this *Tree) analyzeExpression (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
switch expression := expression.(type) {
|
switch expression := expression.(type) {
|
||||||
|
case *entity.Assignment:
|
||||||
|
return this.analyzeAssignment(expression)
|
||||||
case *entity.Variable:
|
case *entity.Variable:
|
||||||
return this.analyzeVariable(into, mode, expression)
|
return this.analyzeVariable(into, mode, expression)
|
||||||
case *entity.Declaration:
|
case *entity.Declaration:
|
||||||
@ -69,22 +71,3 @@ func (this *Tree) analyzeExpression (
|
|||||||
expression, expression))
|
expression, expression))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Tree) analyzeStatement (
|
|
||||||
statement entity.Statement,
|
|
||||||
) (
|
|
||||||
entity.Statement,
|
|
||||||
error,
|
|
||||||
) {
|
|
||||||
if assignment, ok := statement.(*entity.Assignment); ok {
|
|
||||||
return this.analyzeAssignment(assignment)
|
|
||||||
} else if expression, ok := statement.(entity.Expression); ok {
|
|
||||||
expression, err := this.analyzeExpression(nil, strict, expression)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
return expression.(entity.Statement), nil
|
|
||||||
} else {
|
|
||||||
panic(fmt.Sprintf (
|
|
||||||
"BUG: analyzer doesnt know about statement %v, ty: %T",
|
|
||||||
statement, statement))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "github.com/alecthomas/participle/v2"
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
// All expression analysis routines must take in the type they are being
|
// All expression analysis routines must take in the type they are being
|
||||||
@ -9,6 +9,29 @@ import "git.tebibyte.media/sashakoshka/fspl/entity"
|
|||||||
// is nil, the expression must ignore it unless it can do upwards type
|
// is nil, the expression must ignore it unless it can do upwards type
|
||||||
// inference.
|
// inference.
|
||||||
|
|
||||||
|
func (this *Tree) analyzeAssignment (
|
||||||
|
assignment *entity.Assignment,
|
||||||
|
) (
|
||||||
|
entity.Expression,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
// analyze location
|
||||||
|
location, err := this.analyzeExpression(nil, strict, assignment.Location)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
assignment.Location = location
|
||||||
|
|
||||||
|
// ensure location is location expression
|
||||||
|
err = this.isLocationExpression(location)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
// analyze value
|
||||||
|
value, err := this.analyzeExpression(location.Type(), strict, assignment.Value)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
assignment.Value = value
|
||||||
|
|
||||||
|
return assignment, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (this *Tree) analyzeVariable (
|
func (this *Tree) analyzeVariable (
|
||||||
into entity.Type,
|
into entity.Type,
|
||||||
mode strictness,
|
mode strictness,
|
||||||
@ -19,12 +42,12 @@ func (this *Tree) analyzeVariable (
|
|||||||
) {
|
) {
|
||||||
declaration := this.variable(variable.Name)
|
declaration := this.variable(variable.Name)
|
||||||
if declaration == nil {
|
if declaration == nil {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
variable.Pos, "no variable named %s",
|
variable.Position, "no variable named %s",
|
||||||
variable.Name)
|
variable.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := this.canAssign(variable.Pos, into, mode, declaration.Type())
|
err := this.canAssign(variable.Position, into, mode, declaration.Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
variable.Declaration = declaration
|
variable.Declaration = declaration
|
||||||
@ -42,17 +65,17 @@ func (this *Tree) analyzeDeclaration (
|
|||||||
scope, _ := this.topScope()
|
scope, _ := this.topScope()
|
||||||
existing := scope.Variable(declaration.Name)
|
existing := scope.Variable(declaration.Name)
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
declaration.Pos,
|
declaration.Position,
|
||||||
"%s already declared in block at %v",
|
"%s already declared in block at %v",
|
||||||
declaration.Name, existing.Pos)
|
declaration.Name, existing.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty, err := this.analyzeType(declaration.Ty, false)
|
ty, err := this.analyzeType(declaration.Ty, false)
|
||||||
declaration.Ty = ty
|
declaration.Ty = ty
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
err = this.canAssign(declaration.Pos, into, mode, declaration.Type())
|
err = this.canAssign(declaration.Position, into, mode, declaration.Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
this.addVariable(declaration)
|
this.addVariable(declaration)
|
||||||
@ -68,22 +91,22 @@ func (this *Tree) analyzeCall (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
// get function
|
// get function
|
||||||
function, err := this.analyzeFunction(call.Pos, call.Name)
|
function, err := this.analyzeFunction(call.Position, call.Name)
|
||||||
call.Function = function
|
call.Function = function
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
// check return result
|
// check return result
|
||||||
err = this.canAssign(call.Pos, into, mode, function.Signature.Return)
|
err = this.canAssign(call.Position, into, mode, function.Signature.Return)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
// check arg count
|
// check arg count
|
||||||
if len(call.Arguments) > len(function.Signature.Arguments) {
|
if len(call.Arguments) > len(function.Signature.Arguments) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
call.Pos, "too many arguments in call to %s",
|
call.Position, "too many arguments in call to %s",
|
||||||
call.Name)
|
call.Name)
|
||||||
} else if len(call.Arguments) < len(function.Signature.Arguments) {
|
} else if len(call.Arguments) < len(function.Signature.Arguments) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
call.Pos, "too few arguments in call to %s",
|
call.Position, "too few arguments in call to %s",
|
||||||
call.Name)
|
call.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,11 +131,11 @@ func (this *Tree) analyzeMethodCall (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
// get method
|
// get method
|
||||||
sourceExpr, err := this.analyzeVariable(nil, strict, call.Source)
|
sourceExpr, err := this.analyzeExpression(nil, strict, call.Source)
|
||||||
source := sourceExpr.(*entity.Variable)
|
source := sourceExpr.(*entity.Variable)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
method, err := this.analyzeMethodOrBehavior (
|
method, err := this.analyzeMethodOrBehavior (
|
||||||
call.Pos, source.Declaration.Type(), call.Name)
|
call.Position, source.Declaration.Type(), call.Name)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
// extract signature
|
// extract signature
|
||||||
@ -131,17 +154,17 @@ func (this *Tree) analyzeMethodCall (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check return result
|
// check return result
|
||||||
err = this.canAssign(call.Pos, into, mode, signature.Return)
|
err = this.canAssign(call.Position, into, mode, signature.Return)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
// check arg count
|
// check arg count
|
||||||
if len(call.Arguments) > len(signature.Arguments) {
|
if len(call.Arguments) > len(signature.Arguments) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
call.Pos, "too many arguments in call to %s",
|
call.Position, "too many arguments in call to %s",
|
||||||
call.Name)
|
call.Name)
|
||||||
} else if len(call.Arguments) < len(signature.Arguments) {
|
} else if len(call.Arguments) < len(signature.Arguments) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
call.Pos, "too few arguments in call to %s",
|
call.Position, "too few arguments in call to %s",
|
||||||
call.Name)
|
call.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +189,7 @@ func (this *Tree) analyzeSubscript (
|
|||||||
) {
|
) {
|
||||||
slice, err := this.analyzeExpression (
|
slice, err := this.analyzeExpression (
|
||||||
&entity.TypeSlice {
|
&entity.TypeSlice {
|
||||||
Pos: subscript.Pos,
|
Position: subscript.Position,
|
||||||
Element: into,
|
Element: into,
|
||||||
}, weak,
|
}, weak,
|
||||||
subscript.Slice)
|
subscript.Slice)
|
||||||
@ -254,7 +277,7 @@ func (this *Tree) analyzeDereference (
|
|||||||
) {
|
) {
|
||||||
pointer, err := this.analyzeExpression (
|
pointer, err := this.analyzeExpression (
|
||||||
&entity.TypePointer {
|
&entity.TypePointer {
|
||||||
Pos: dereference.Pos,
|
Position: dereference.Position,
|
||||||
Referenced: into,
|
Referenced: into,
|
||||||
}, weak,
|
}, weak,
|
||||||
dereference.Pointer)
|
dereference.Pointer)
|
||||||
@ -288,7 +311,7 @@ func (this *Tree) analyzeReference (
|
|||||||
) {
|
) {
|
||||||
referenced, ok := into.(*entity.TypePointer)
|
referenced, ok := into.(*entity.TypePointer)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, participle.Errorf(reference.Pos, "expected %v", into)
|
return nil, errors.Errorf(reference.Position, "expected %v", into)
|
||||||
}
|
}
|
||||||
|
|
||||||
value, err := this.analyzeExpression (
|
value, err := this.analyzeExpression (
|
||||||
@ -315,7 +338,7 @@ func (this *Tree) analyzeValueCast (
|
|||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
cast.Ty = ty
|
cast.Ty = ty
|
||||||
|
|
||||||
err = this.canAssign(cast.Pos, into, mode, cast.Type())
|
err = this.canAssign(cast.Position, into, mode, cast.Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
value, err := this.analyzeExpression(cast.Ty, coerce, cast.Value)
|
value, err := this.analyzeExpression(cast.Ty, coerce, cast.Value)
|
||||||
@ -337,7 +360,7 @@ func (this *Tree) analyzeBitCast (
|
|||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
cast.Ty = ty
|
cast.Ty = ty
|
||||||
|
|
||||||
err = this.canAssign(cast.Pos, into, mode, cast.Type())
|
err = this.canAssign(cast.Position, into, mode, cast.Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
value, err := this.analyzeExpression(cast.Ty, force, cast.Value)
|
value, err := this.analyzeExpression(cast.Ty, force, cast.Value)
|
||||||
@ -356,12 +379,12 @@ func (this *Tree) analyzeOperation (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
wrongInto := func () (entity.Expression, error) {
|
wrongInto := func () (entity.Expression, error) {
|
||||||
return nil, participle.Errorf(operation.Pos, "expected %v", into)
|
return nil, errors.Errorf(operation.Position, "expected %v", into)
|
||||||
}
|
}
|
||||||
|
|
||||||
wrongArgCount := func () (entity.Expression, error) {
|
wrongArgCount := func () (entity.Expression, error) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
operation.Pos, "wrong argument count for %v",
|
operation.Position, "wrong argument count for %v",
|
||||||
operation.Operator)
|
operation.Operator)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,8 +436,8 @@ func (this *Tree) analyzeOperation (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if argumentType == nil {
|
if argumentType == nil {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
operation.Pos,
|
operation.Position,
|
||||||
"operation arguments have ambiguous type")
|
"operation arguments have ambiguous type")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,8 +533,8 @@ func (this *Tree) analyzeBlock (
|
|||||||
defer this.popScope()
|
defer this.popScope()
|
||||||
|
|
||||||
if len(block.Steps) == 0 && into != nil {
|
if len(block.Steps) == 0 && into != nil {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
block.Pos, "block must have at least one statement")
|
block.Position, "block must have at least one statement")
|
||||||
}
|
}
|
||||||
|
|
||||||
final := len(block.Steps) - 1
|
final := len(block.Steps) - 1
|
||||||
@ -519,8 +542,8 @@ func (this *Tree) analyzeBlock (
|
|||||||
if index == final && into != nil {
|
if index == final && into != nil {
|
||||||
expression, ok := step.(entity.Expression)
|
expression, ok := step.(entity.Expression)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
block.Pos, "expected expression")
|
block.Position, "expected expression")
|
||||||
}
|
}
|
||||||
|
|
||||||
step, err := this.analyzeExpression(into, strict, expression)
|
step, err := this.analyzeExpression(into, strict, expression)
|
||||||
@ -528,7 +551,7 @@ func (this *Tree) analyzeBlock (
|
|||||||
block.Steps[index] = step
|
block.Steps[index] = step
|
||||||
block.Ty = step.Type()
|
block.Ty = step.Type()
|
||||||
} else {
|
} else {
|
||||||
step, err := this.analyzeStatement(step)
|
step, err := this.analyzeExpression(nil, strict, step)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
block.Steps[index] = step
|
block.Steps[index] = step
|
||||||
}
|
}
|
||||||
@ -555,22 +578,22 @@ func (this *Tree) analyzeMemberAccess (
|
|||||||
case *entity.TypePointer:
|
case *entity.TypePointer:
|
||||||
referenced, ok := ReduceToBase(sourceTypeAny.Referenced).(*entity.TypeStruct)
|
referenced, ok := ReduceToBase(sourceTypeAny.Referenced).(*entity.TypeStruct)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
access.Pos, "cannot access members of %v", source)
|
access.Position, "cannot access members of %v", source)
|
||||||
}
|
}
|
||||||
sourceType = referenced
|
sourceType = referenced
|
||||||
default:
|
default:
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
access.Pos, "cannot access members of %v", source)
|
access.Position, "cannot access members of %v", source)
|
||||||
}
|
}
|
||||||
|
|
||||||
member, ok := sourceType.MemberMap[access.Member]
|
member, ok := sourceType.MemberMap[access.Member]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
access.Pos, "no member %v", access)
|
access.Position, "no member %v", access)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = this.canAssign(access.Pos, into, mode, member.Type())
|
err = this.canAssign(access.Position, into, mode, member.Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
access.Ty = member.Type()
|
access.Ty = member.Type()
|
||||||
|
|
||||||
@ -600,8 +623,8 @@ func (this *Tree) analyzeIfElse (
|
|||||||
|
|
||||||
if ifelse.False == nil {
|
if ifelse.False == nil {
|
||||||
if into != nil {
|
if into != nil {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
ifelse.Pos,
|
ifelse.Position,
|
||||||
"else case required when using value of if ")
|
"else case required when using value of if ")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -643,20 +666,20 @@ func (this *Tree) analyzeBreak (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
if into != nil {
|
if into != nil {
|
||||||
return nil, participle.Errorf(brk.Pos, "expected %v", into)
|
return nil, errors.Errorf(brk.Position, "expected %v", into)
|
||||||
}
|
}
|
||||||
|
|
||||||
loop, ok := this.topLoop()
|
loop, ok := this.topLoop()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
brk.Pos,
|
brk.Position,
|
||||||
"break statement must be within loop")
|
"break statement must be within loop")
|
||||||
}
|
}
|
||||||
brk.Loop = loop
|
brk.Loop = loop
|
||||||
|
|
||||||
if loop.Type() != nil && brk.Value == nil {
|
if loop.Type() != nil && brk.Value == nil {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
brk.Pos,
|
brk.Position,
|
||||||
"break statement must have value")
|
"break statement must have value")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,7 +701,7 @@ func (this *Tree) analyzeReturn (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
if into != nil {
|
if into != nil {
|
||||||
return nil, participle.Errorf(ret.Pos, "expected %v", into)
|
return nil, errors.Errorf(ret.Position, "expected %v", into)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.Declaration, _ = this.topDeclaration()
|
ret.Declaration, _ = this.topDeclaration()
|
||||||
@ -691,8 +714,8 @@ func (this *Tree) analyzeReturn (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ty != nil && ret.Value == nil {
|
if ty != nil && ret.Value == nil {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
ret.Pos,
|
ret.Position,
|
||||||
"break statement must have value")
|
"break statement must have value")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import "github.com/alecthomas/participle/v2"
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||||
import "github.com/alecthomas/participle/v2/lexer"
|
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
func (this *Tree) analyzeFunction (
|
func (this *Tree) analyzeFunction (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
name string,
|
name string,
|
||||||
) (
|
) (
|
||||||
*entity.Function,
|
*entity.Function,
|
||||||
@ -21,7 +20,7 @@ func (this *Tree) analyzeFunction (
|
|||||||
// error if function is missing
|
// error if function is missing
|
||||||
function, exists := this.rawFunctions[name]
|
function, exists := this.rawFunctions[name]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, participle.Errorf(pos, "no function named %s", name)
|
return nil, errors.Errorf(pos, "no function named %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new scope context for this function
|
// create a new scope context for this function
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import "unicode/utf16"
|
import "unicode/utf16"
|
||||||
import "github.com/alecthomas/participle/v2"
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
func (this *Tree) analyzeLiteralInt (
|
func (this *Tree) analyzeLiteralInt (
|
||||||
@ -13,14 +13,14 @@ func (this *Tree) analyzeLiteralInt (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
if !isNumeric(into) {
|
if !isNumeric(into) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos, "cannot use integer literal as %v",
|
literal.Position, "cannot use integer literal as %v",
|
||||||
into)
|
into)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isInteger(into) && !inRange(into, int64(literal.Value)) {
|
if isInteger(into) && !inRange(into, int64(literal.Value)) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos, "integer literal out of range for type %v",
|
literal.Position, "integer literal out of range for type %v",
|
||||||
into)
|
into)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ func (this *Tree) analyzeLiteralFloat (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
if !isFloat(into) {
|
if !isFloat(into) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos, "cannot use float literal as %v",
|
literal.Position, "cannot use float literal as %v",
|
||||||
into)
|
into)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,8 +57,8 @@ func (this *Tree) analyzeLiteralString (
|
|||||||
base := ReduceToBase(into)
|
base := ReduceToBase(into)
|
||||||
|
|
||||||
errCantUse := func () error {
|
errCantUse := func () error {
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
literal.Pos, "cannot use string literal as %v",
|
literal.Position, "cannot use string literal as %v",
|
||||||
into)
|
into)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,14 +82,14 @@ func (this *Tree) analyzeLiteralString (
|
|||||||
length = len(literal.ValueUTF8)
|
length = len(literal.ValueUTF8)
|
||||||
}
|
}
|
||||||
if length > 1 {
|
if length > 1 {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos,
|
literal.Position,
|
||||||
"cannot fit string literal of length " +
|
"cannot fit string literal of length " +
|
||||||
"%v into %v",
|
"%v into %v",
|
||||||
length, into)
|
length, into)
|
||||||
} else if length < 1 {
|
} else if length < 1 {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos,
|
literal.Position,
|
||||||
"string literal must have data when " +
|
"string literal must have data when " +
|
||||||
"assigning to %v",
|
"assigning to %v",
|
||||||
into)
|
into)
|
||||||
@ -108,8 +108,8 @@ func (this *Tree) analyzeLiteralString (
|
|||||||
length = len(literal.ValueUTF8)
|
length = len(literal.ValueUTF8)
|
||||||
}
|
}
|
||||||
if length > base.Length {
|
if length > base.Length {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos,
|
literal.Position,
|
||||||
"cannot fit string literal of length " +
|
"cannot fit string literal of length " +
|
||||||
"%v into array of length %v",
|
"%v into array of length %v",
|
||||||
length, base.Length)
|
length, base.Length)
|
||||||
@ -160,8 +160,8 @@ func (this *Tree) analyzeLiteralArray (
|
|||||||
case *entity.TypeArray:
|
case *entity.TypeArray:
|
||||||
base := base.(*entity.TypeArray)
|
base := base.(*entity.TypeArray)
|
||||||
if base.Length < len(literal.Elements) {
|
if base.Length < len(literal.Elements) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos, "expected %v elements or less",
|
literal.Position, "expected %v elements or less",
|
||||||
base.Length)
|
base.Length)
|
||||||
}
|
}
|
||||||
elementType = base.Element
|
elementType = base.Element
|
||||||
@ -174,8 +174,8 @@ func (this *Tree) analyzeLiteralArray (
|
|||||||
base := base.(*entity.TypePointer)
|
base := base.(*entity.TypePointer)
|
||||||
elementType = base.Referenced
|
elementType = base.Referenced
|
||||||
default:
|
default:
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos, "cannot use array literal as %v",
|
literal.Position, "cannot use array literal as %v",
|
||||||
into)
|
into)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,8 +199,8 @@ func (this *Tree) analyzeLiteralStruct (
|
|||||||
) {
|
) {
|
||||||
base, ok := ReduceToBase(into).(*entity.TypeStruct)
|
base, ok := ReduceToBase(into).(*entity.TypeStruct)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos, "cannot use struct literal as %v",
|
literal.Position, "cannot use struct literal as %v",
|
||||||
into)
|
into)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,8 +210,8 @@ func (this *Tree) analyzeLiteralStruct (
|
|||||||
for name, member := range literal.MemberMap {
|
for name, member := range literal.MemberMap {
|
||||||
correct, ok := base.MemberMap[name]
|
correct, ok := base.MemberMap[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos, "no member %v.%s",
|
literal.Position, "no member %v.%s",
|
||||||
into, name)
|
into, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,8 +233,8 @@ func (this *Tree) analyzeLiteralBoolean (
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
if !isBoolean(into) {
|
if !isBoolean(into) {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
literal.Pos, "cannot use boolean literal as %v",
|
literal.Position, "cannot use boolean literal as %v",
|
||||||
into)
|
into)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,9 +264,9 @@ func (this *Tree) assembleStructLiteralMap (
|
|||||||
literal.MemberOrder = make([]string, len(literal.Members))
|
literal.MemberOrder = make([]string, len(literal.Members))
|
||||||
for index, member := range literal.Members {
|
for index, member := range literal.Members {
|
||||||
if previous, exists := literal.MemberMap[member.Name]; exists {
|
if previous, exists := literal.MemberMap[member.Name]; exists {
|
||||||
return literal, participle.Errorf (
|
return literal, errors.Errorf (
|
||||||
member.Pos, "%s already listed in struct literal at %v",
|
member.Position, "%s already listed in struct literal at %v",
|
||||||
member.Name, previous.Pos)
|
member.Name, previous.Position)
|
||||||
}
|
}
|
||||||
literal.MemberMap [member.Name] = member
|
literal.MemberMap [member.Name] = member
|
||||||
literal.MemberOrder[index] = member.Name
|
literal.MemberOrder[index] = member.Name
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "github.com/alecthomas/participle/v2"
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||||
import "github.com/alecthomas/participle/v2/lexer"
|
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
// analyzeMethod analyzes a method that is directly owned by the specified type.
|
// analyzeMethod analyzes a method that is directly owned by the specified type.
|
||||||
func (this *Tree) analyzeMethod (
|
func (this *Tree) analyzeMethod (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
typeName string,
|
typeName string,
|
||||||
name string,
|
name string,
|
||||||
) (
|
) (
|
||||||
@ -26,7 +25,7 @@ func (this *Tree) analyzeMethod (
|
|||||||
// error if method is missing
|
// error if method is missing
|
||||||
method, exists := this.rawMethods[typeName + "." + name]
|
method, exists := this.rawMethods[typeName + "." + name]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
pos, "no method named %s.%s",
|
pos, "no method named %s.%s",
|
||||||
typeName, name)
|
typeName, name)
|
||||||
}
|
}
|
||||||
@ -52,12 +51,12 @@ func (this *Tree) analyzeMethod (
|
|||||||
|
|
||||||
// add owner to method
|
// add owner to method
|
||||||
method.This = &entity.Declaration {
|
method.This = &entity.Declaration {
|
||||||
Pos: method.Pos,
|
Position: method.Position,
|
||||||
Name: "this",
|
Name: "this",
|
||||||
Ty: &entity.TypePointer {
|
Ty: &entity.TypePointer {
|
||||||
Pos: method.Pos,
|
Position: method.Position,
|
||||||
Referenced: &entity.TypeNamed {
|
Referenced: &entity.TypeNamed {
|
||||||
Pos: method.Pos,
|
Position: method.Position,
|
||||||
Name: typeName,
|
Name: typeName,
|
||||||
Type: owner.Type,
|
Type: owner.Type,
|
||||||
},
|
},
|
||||||
@ -88,7 +87,7 @@ func (this *Tree) methodExists (typeName, name string) bool {
|
|||||||
// analyzeMethodOrBehavior returns *entity.Signature if it found an interface
|
// analyzeMethodOrBehavior returns *entity.Signature if it found an interface
|
||||||
// behavior, and *entity.Method if it found a method.
|
// behavior, and *entity.Method if it found a method.
|
||||||
func (this *Tree) analyzeMethodOrBehavior (
|
func (this *Tree) analyzeMethodOrBehavior (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
ty entity.Type,
|
ty entity.Type,
|
||||||
name string,
|
name string,
|
||||||
) (
|
) (
|
||||||
@ -99,7 +98,7 @@ func (this *Tree) analyzeMethodOrBehavior (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *Tree) analyzeMethodOrBehaviorInternal (
|
func (this *Tree) analyzeMethodOrBehaviorInternal (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
ty entity.Type,
|
ty entity.Type,
|
||||||
name string,
|
name string,
|
||||||
pierceReference bool,
|
pierceReference bool,
|
||||||
@ -124,7 +123,7 @@ func (this *Tree) analyzeMethodOrBehaviorInternal (
|
|||||||
if behavior, ok := ty.BehaviorMap[name]; ok {
|
if behavior, ok := ty.BehaviorMap[name]; ok {
|
||||||
return behavior, nil
|
return behavior, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
pos, "no behavior or method named %s",
|
pos, "no behavior or method named %s",
|
||||||
name)
|
name)
|
||||||
}
|
}
|
||||||
@ -135,7 +134,7 @@ func (this *Tree) analyzeMethodOrBehaviorInternal (
|
|||||||
return this.analyzeMethodOrBehaviorInternal (
|
return this.analyzeMethodOrBehaviorInternal (
|
||||||
pos, ty.Referenced, name, false)
|
pos, ty.Referenced, name, false)
|
||||||
} else {
|
} else {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
pos, "no method named %s defined on this type",
|
pos, "no method named %s defined on this type",
|
||||||
name)
|
name)
|
||||||
}
|
}
|
||||||
@ -147,7 +146,7 @@ func (this *Tree) analyzeMethodOrBehaviorInternal (
|
|||||||
*entity.TypeFloat,
|
*entity.TypeFloat,
|
||||||
*entity.TypeWord:
|
*entity.TypeWord:
|
||||||
|
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
pos, "no method named %s defined on this type",
|
pos, "no method named %s defined on this type",
|
||||||
name)
|
name)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import "github.com/alecthomas/participle/v2"
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
func (this *Tree) assembleSignatureMap (signature *entity.Signature) (*entity.Signature, error) {
|
func (this *Tree) assembleSignatureMap (signature *entity.Signature) (*entity.Signature, error) {
|
||||||
@ -8,9 +8,9 @@ func (this *Tree) assembleSignatureMap (signature *entity.Signature) (*entity.Si
|
|||||||
signature.ArgumentOrder = make([]string, len(signature.Arguments))
|
signature.ArgumentOrder = make([]string, len(signature.Arguments))
|
||||||
for index, member := range signature.Arguments {
|
for index, member := range signature.Arguments {
|
||||||
if previous, exists := signature.ArgumentMap[member.Name]; exists {
|
if previous, exists := signature.ArgumentMap[member.Name]; exists {
|
||||||
return signature, participle.Errorf (
|
return signature, errors.Errorf (
|
||||||
member.Pos, "%s already listed as argument at %v",
|
member.Position, "%s already listed as argument at %v",
|
||||||
member.Name, previous.Pos)
|
member.Name, previous.Position)
|
||||||
}
|
}
|
||||||
signature.ArgumentMap [member.Name] = member
|
signature.ArgumentMap [member.Name] = member
|
||||||
signature.ArgumentOrder[index] = member.Name
|
signature.ArgumentOrder[index] = member.Name
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
package analyzer
|
|
||||||
|
|
||||||
// import "fmt"
|
|
||||||
//import "github.com/alecthomas/participle/v2"
|
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
|
||||||
|
|
||||||
func (this *Tree) analyzeAssignment (
|
|
||||||
assignment *entity.Assignment,
|
|
||||||
) (
|
|
||||||
entity.Statement,
|
|
||||||
error,
|
|
||||||
) {
|
|
||||||
// analyze location
|
|
||||||
location, err := this.analyzeExpression(nil, strict, assignment.Location)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
assignment.Location = location
|
|
||||||
|
|
||||||
// ensure location is location expression
|
|
||||||
err = this.isLocationExpression(location)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
|
|
||||||
// analyze value
|
|
||||||
value, err := this.analyzeExpression(location.Type(), strict, assignment.Value)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
assignment.Value = value
|
|
||||||
|
|
||||||
return assignment, nil
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import "github.com/alecthomas/participle/v2"
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||||
import "github.com/alecthomas/participle/v2/lexer"
|
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/parser"
|
import "git.tebibyte.media/sashakoshka/fspl/parser"
|
||||||
|
|
||||||
@ -36,21 +35,21 @@ func (this *Tree) assembleRawMaps () error {
|
|||||||
switch declaration.(type) {
|
switch declaration.(type) {
|
||||||
case *entity.Typedef:
|
case *entity.Typedef:
|
||||||
ty := declaration.(*entity.Typedef)
|
ty := declaration.(*entity.Typedef)
|
||||||
err := this.topLevelNameAvailable(ty.Pos, ty.Name)
|
err := this.topLevelNameAvailable(ty.Position, ty.Name)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
ty.Methods = make(map[string] *entity.Method)
|
ty.Methods = make(map[string] *entity.Method)
|
||||||
this.rawTypes[ty.Name] = ty
|
this.rawTypes[ty.Name] = ty
|
||||||
case *entity.Function:
|
case *entity.Function:
|
||||||
function := declaration.(*entity.Function)
|
function := declaration.(*entity.Function)
|
||||||
err := this.topLevelNameAvailable (
|
err := this.topLevelNameAvailable (
|
||||||
function.Pos,
|
function.Position,
|
||||||
function.Signature.Name)
|
function.Signature.Name)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
this.rawFunctions[function.Signature.Name] = function
|
this.rawFunctions[function.Signature.Name] = function
|
||||||
case *entity.Method:
|
case *entity.Method:
|
||||||
method := declaration.(*entity.Method)
|
method := declaration.(*entity.Method)
|
||||||
name := method.TypeName + "." + method.Signature.Name
|
name := method.TypeName + "." + method.Signature.Name
|
||||||
err := this.topLevelNameAvailable(method.Pos, name)
|
err := this.topLevelNameAvailable(method.Position, name)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
this.rawMethods[name] = method
|
this.rawMethods[name] = method
|
||||||
}
|
}
|
||||||
@ -58,48 +57,48 @@ func (this *Tree) assembleRawMaps () error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Tree) topLevelNameAvailable (currentPos lexer.Position, name string) error {
|
func (this *Tree) topLevelNameAvailable (currentPos errors.Position, name string) error {
|
||||||
if _, isPrimitive := primitiveTypes[name]; isPrimitive {
|
if _, isPrimitive := primitiveTypes[name]; isPrimitive {
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
currentPos, "cannot shadow primitive %s",
|
currentPos, "cannot shadow primitive %s",
|
||||||
name)
|
name)
|
||||||
}
|
}
|
||||||
if _, isBuiltin := builtinTypes[name]; isBuiltin {
|
if _, isBuiltin := builtinTypes[name]; isBuiltin {
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
currentPos, "cannot shadow builtin %s",
|
currentPos, "cannot shadow builtin %s",
|
||||||
name)
|
name)
|
||||||
}
|
}
|
||||||
if ty, isType := this.rawTypes[name]; isType {
|
if ty, isType := this.rawTypes[name]; isType {
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
currentPos, "%s already declared at %v",
|
currentPos, "%s already declared at %v",
|
||||||
name, ty.Pos)
|
name, ty.Position)
|
||||||
}
|
}
|
||||||
if function, isFunction := this.rawFunctions[name]; isFunction {
|
if function, isFunction := this.rawFunctions[name]; isFunction {
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
currentPos, "%s already declared at %v",
|
currentPos, "%s already declared at %v",
|
||||||
name, function.Pos)
|
name, function.Position)
|
||||||
}
|
}
|
||||||
if method, isMethod := this.rawMethods[name]; isMethod {
|
if method, isMethod := this.rawMethods[name]; isMethod {
|
||||||
return participle.Errorf (
|
return errors.Errorf (
|
||||||
currentPos, "%s already declared at %v",
|
currentPos, "%s already declared at %v",
|
||||||
name, method.Pos)
|
name, method.Position)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Tree) analyzeDeclarations () error {
|
func (this *Tree) analyzeDeclarations () error {
|
||||||
for name, rawType := range this.rawTypes {
|
for name, rawType := range this.rawTypes {
|
||||||
ty, err := this.analyzeTypedef(rawType.Pos, name, false)
|
ty, err := this.analyzeTypedef(rawType.Position, name, false)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
this.Types[name] = ty
|
this.Types[name] = ty
|
||||||
}
|
}
|
||||||
for name, rawFunction := range this.rawFunctions {
|
for name, rawFunction := range this.rawFunctions {
|
||||||
_, err := this.analyzeFunction(rawFunction.Pos, name)
|
_, err := this.analyzeFunction(rawFunction.Position, name)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
}
|
}
|
||||||
for _, rawMethod := range this.rawMethods {
|
for _, rawMethod := range this.rawMethods {
|
||||||
_, err := this.analyzeMethod (
|
_, err := this.analyzeMethod (
|
||||||
rawMethod.Pos,
|
rawMethod.Position,
|
||||||
rawMethod.TypeName,
|
rawMethod.TypeName,
|
||||||
rawMethod.Signature.Name)
|
rawMethod.Signature.Name)
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
@ -117,9 +116,8 @@ func (this *Tree) ensure () {
|
|||||||
this.Functions = make(map[string] *entity.Function)
|
this.Functions = make(map[string] *entity.Function)
|
||||||
|
|
||||||
for name, ty := range builtinTypes {
|
for name, ty := range builtinTypes {
|
||||||
access := entity.AccessPublic
|
|
||||||
this.Types[name] = &entity.Typedef {
|
this.Types[name] = &entity.Typedef {
|
||||||
Acc: &access,
|
Acc: entity.AccessPublic,
|
||||||
Name: name,
|
Name: name,
|
||||||
Type: ty,
|
Type: ty,
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "github.com/alecthomas/participle/v2"
|
import "git.tebibyte.media/sashakoshka/fspl/errors"
|
||||||
import "github.com/alecthomas/participle/v2/lexer"
|
|
||||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||||
|
|
||||||
func (this *Tree) analyzeTypedef (
|
func (this *Tree) analyzeTypedef (
|
||||||
pos lexer.Position,
|
pos errors.Position,
|
||||||
name string,
|
name string,
|
||||||
acceptIncomplete bool,
|
acceptIncomplete bool,
|
||||||
) (
|
) (
|
||||||
@ -23,7 +22,7 @@ func (this *Tree) analyzeTypedef (
|
|||||||
if acceptIncomplete {
|
if acceptIncomplete {
|
||||||
return definition, nil
|
return definition, nil
|
||||||
} else {
|
} else {
|
||||||
return nil, participle.Errorf (
|
return nil, errors.Errorf (
|
||||||
pos, "type %s cannot be used in this context",
|
pos, "type %s cannot be used in this context",
|
||||||
name)
|
name)
|
||||||
}
|
}
|
||||||
@ -32,7 +31,7 @@ func (this *Tree) analyzeTypedef (
|
|||||||
// error if type is missing
|
// error if type is missing
|
||||||
definition, exists := this.rawTypes[name]
|
definition, exists := this.rawTypes[name]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, participle.Errorf(pos, "no type named %s", name)
|
return nil, errors.Errorf(pos, "no type named %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -83,7 +82,7 @@ func (this *Tree) analyzeTypeInternal (
|
|||||||
return primitive, nil
|
return primitive, nil
|
||||||
}
|
}
|
||||||
var def *entity.Typedef
|
var def *entity.Typedef
|
||||||
def, err = this.analyzeTypedef(ty.Pos, ty.Name, acceptIncomplete)
|
def, err = this.analyzeTypedef(ty.Position, ty.Name, acceptIncomplete)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ty.Type = def.Type
|
ty.Type = def.Type
|
||||||
}
|
}
|
||||||
@ -108,8 +107,8 @@ func (this *Tree) analyzeTypeInternal (
|
|||||||
ty := ty.(*entity.TypeArray)
|
ty := ty.(*entity.TypeArray)
|
||||||
updateIncompleteInfo()
|
updateIncompleteInfo()
|
||||||
if ty.Length < 1 {
|
if ty.Length < 1 {
|
||||||
return ty, participle.Errorf (
|
return ty, errors.Errorf (
|
||||||
ty.Pos, "array length must be > 0")
|
ty.Position, "array length must be > 0")
|
||||||
}
|
}
|
||||||
ty.Element, err = this.analyzeType(ty.Element, false)
|
ty.Element, err = this.analyzeType(ty.Element, false)
|
||||||
return ty, err
|
return ty, err
|
||||||
@ -144,8 +143,8 @@ func (this *Tree) analyzeTypeInternal (
|
|||||||
ty := ty.(*entity.TypeInt)
|
ty := ty.(*entity.TypeInt)
|
||||||
updateIncompleteInfo()
|
updateIncompleteInfo()
|
||||||
if ty.Width < 1 {
|
if ty.Width < 1 {
|
||||||
return ty, participle.Errorf (
|
return ty, errors.Errorf (
|
||||||
ty.Pos, "integer width must be > 0")
|
ty.Position, "integer width must be > 0")
|
||||||
}
|
}
|
||||||
return ty, nil
|
return ty, nil
|
||||||
|
|
||||||
@ -162,9 +161,9 @@ func (this *Tree) assembleStructMap (ty *entity.TypeStruct) (*entity.TypeStruct,
|
|||||||
ty.MemberOrder = make([]string, len(ty.Members))
|
ty.MemberOrder = make([]string, len(ty.Members))
|
||||||
for index, member := range ty.Members {
|
for index, member := range ty.Members {
|
||||||
if previous, exists := ty.MemberMap[member.Name]; exists {
|
if previous, exists := ty.MemberMap[member.Name]; exists {
|
||||||
return ty, participle.Errorf (
|
return ty, errors.Errorf (
|
||||||
member.Pos, "%s already listed in struct at %v",
|
member.Position, "%s already listed in struct at %v",
|
||||||
member.Name, previous.Pos)
|
member.Name, previous.Position)
|
||||||
}
|
}
|
||||||
ty.MemberMap [member.Name] = member
|
ty.MemberMap [member.Name] = member
|
||||||
ty.MemberOrder[index] = member.Name
|
ty.MemberOrder[index] = member.Name
|
||||||
@ -178,9 +177,9 @@ func (this *Tree) assembleInterfaceMap (ty *entity.TypeInterface) (*entity.TypeI
|
|||||||
ty.BehaviorOrder = make([]string, len(ty.Behaviors))
|
ty.BehaviorOrder = make([]string, len(ty.Behaviors))
|
||||||
for index, method := range ty.Behaviors {
|
for index, method := range ty.Behaviors {
|
||||||
if previous, exists := ty.BehaviorMap[method.Name]; exists {
|
if previous, exists := ty.BehaviorMap[method.Name]; exists {
|
||||||
return ty, participle.Errorf (
|
return ty, errors.Errorf (
|
||||||
method.Pos, "%s already listed in interface at %v",
|
method.Position, "%s already listed in interface at %v",
|
||||||
method.Name, previous.Pos)
|
method.Name, previous.Position)
|
||||||
}
|
}
|
||||||
ty.BehaviorMap [method.Name] = method
|
ty.BehaviorMap [method.Name] = method
|
||||||
ty.BehaviorOrder[index] = method.Name
|
ty.BehaviorOrder[index] = method.Name
|
||||||
|
Loading…
Reference in New Issue
Block a user