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