Analyze more expressions
This commit is contained in:
parent
2018ccead6
commit
b8d573f2cd
@ -34,14 +34,14 @@ func (this *Tree) analyzeExpression (
|
|||||||
return this.analyzeBitCast(into, mode, expression.(*entity.BitCast))
|
return this.analyzeBitCast(into, mode, expression.(*entity.BitCast))
|
||||||
case *entity.Operation:
|
case *entity.Operation:
|
||||||
return this.analyzeOperation(into, mode, expression.(*entity.Operation))
|
return this.analyzeOperation(into, mode, expression.(*entity.Operation))
|
||||||
// case *entity.Block:
|
case *entity.Block:
|
||||||
// return this.analyzeBlock(into, mode, expression.(*entity.Block))
|
return this.analyzeBlock(into, mode, expression.(*entity.Block))
|
||||||
// case *entity.MemberAccess:
|
case *entity.MemberAccess:
|
||||||
// return this.analyzeMemberAccess(into, mode, expression.(*entity.MemberAccess))
|
return this.analyzeMemberAccess(into, mode, expression.(*entity.MemberAccess))
|
||||||
// case *entity.IfElse:
|
case *entity.IfElse:
|
||||||
// return this.analyzeIfElse(into, mode, expression.(*entity.IfElse))
|
return this.analyzeIfElse(into, mode, expression.(*entity.IfElse))
|
||||||
// case *entity.Loop:
|
case *entity.Loop:
|
||||||
// return this.analyzeLoop(into, mode, expression.(*entity.Loop))
|
return this.analyzeLoop(into, mode, expression.(*entity.Loop))
|
||||||
// case *entity.Break:
|
// case *entity.Break:
|
||||||
// return this.analyzeBreak(into, mode, expression.(*entity.Break))
|
// return this.analyzeBreak(into, mode, expression.(*entity.Break))
|
||||||
// case *entity.Return:
|
// case *entity.Return:
|
||||||
|
@ -17,7 +17,7 @@ func (this *Tree) analyzeVariable (
|
|||||||
entity.Expression,
|
entity.Expression,
|
||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
declaration := this.Variable(variable.Name)
|
declaration := this.variable(variable.Name)
|
||||||
if declaration == nil {
|
if declaration == nil {
|
||||||
return nil, participle.Errorf (
|
return nil, participle.Errorf (
|
||||||
variable.Pos, "no variable named %s",
|
variable.Pos, "no variable named %s",
|
||||||
@ -39,7 +39,7 @@ func (this *Tree) analyzeDeclaration (
|
|||||||
entity.Expression,
|
entity.Expression,
|
||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
existing := this.TopScope().Variable(declaration.Name)
|
existing := this.topScope().Variable(declaration.Name)
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
return nil, participle.Errorf (
|
return nil, participle.Errorf (
|
||||||
declaration.Pos,
|
declaration.Pos,
|
||||||
@ -54,7 +54,7 @@ func (this *Tree) analyzeDeclaration (
|
|||||||
err = this.canAssign(declaration.Pos, into, mode, declaration.Type())
|
err = this.canAssign(declaration.Pos, into, mode, declaration.Type())
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
this.AddVariable(declaration)
|
this.addVariable(declaration)
|
||||||
return &entity.Variable {
|
return &entity.Variable {
|
||||||
Pos: declaration.Pos,
|
Pos: declaration.Pos,
|
||||||
Name: declaration.Name,
|
Name: declaration.Name,
|
||||||
@ -354,7 +354,42 @@ func (this *Tree) analyzeOperation (
|
|||||||
if !this.isBoolean(into) { return wrongInto() }
|
if !this.isBoolean(into) { return wrongInto() }
|
||||||
operation.Ty = &entity.TypeBool { }
|
operation.Ty = &entity.TypeBool { }
|
||||||
|
|
||||||
// TODO
|
// find the first argument that has explicit type information.
|
||||||
|
// TODO: possibly make a method of expressions to check this
|
||||||
|
// without analyzing anything
|
||||||
|
boss := -1
|
||||||
|
var argumentType entity.Type
|
||||||
|
for index, argument := range operation.Arguments {
|
||||||
|
argument, err := this.analyzeExpression(nil, strict, argument)
|
||||||
|
if err == nil {
|
||||||
|
boss = index
|
||||||
|
operation.Arguments[index] = argument
|
||||||
|
argumentType = argument.Type()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if argumentType == nil {
|
||||||
|
return nil, participle.Errorf (
|
||||||
|
operation.Pos,
|
||||||
|
"operation arguments have ambiguous type",
|
||||||
|
operation.Operator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// analyze all remaining arguments
|
||||||
|
for index, argument := range operation.Arguments {
|
||||||
|
if index == boss { continue }
|
||||||
|
|
||||||
|
argument, err := this.analyzeExpression (
|
||||||
|
argumentType, strict, argument)
|
||||||
|
if err != nil {
|
||||||
|
boss = index
|
||||||
|
operation.Arguments[index] = argument
|
||||||
|
break
|
||||||
|
}
|
||||||
|
operation.Arguments[index] = argument
|
||||||
|
}
|
||||||
|
|
||||||
|
return operation, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch operation.Operator {
|
switch operation.Operator {
|
||||||
@ -419,3 +454,124 @@ func (this *Tree) analyzeOperation (
|
|||||||
operation.Operator))
|
operation.Operator))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Tree) analyzeBlock (
|
||||||
|
into entity.Type,
|
||||||
|
mode strictness,
|
||||||
|
block *entity.Block,
|
||||||
|
) (
|
||||||
|
entity.Expression,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
this.pushScope(block)
|
||||||
|
defer this.popScope()
|
||||||
|
|
||||||
|
if len(block.Steps) == 0 && into != nil {
|
||||||
|
return nil, participle.Errorf (
|
||||||
|
block.Pos, "block must have at least one statement")
|
||||||
|
}
|
||||||
|
|
||||||
|
final := len(block.Steps) - 1
|
||||||
|
for index, step := range block.Steps {
|
||||||
|
if index == final && into != nil {
|
||||||
|
expression, ok := step.(entity.Expression)
|
||||||
|
if !ok {
|
||||||
|
return nil, participle.Errorf (
|
||||||
|
block.Pos, "expected expression")
|
||||||
|
}
|
||||||
|
|
||||||
|
step, err := this.analyzeExpression(into, strict, expression)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
block.Steps[index] = step
|
||||||
|
} else {
|
||||||
|
step, err := this.analyzeStatement(step)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
block.Steps[index] = step
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block.Ty = into
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Tree) analyzeMemberAccess (
|
||||||
|
into entity.Type,
|
||||||
|
mode strictness,
|
||||||
|
access *entity.MemberAccess,
|
||||||
|
) (
|
||||||
|
entity.Expression,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
source, err := this.analyzeExpression(nil, strict, access.Source)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
access.Source = source.(*entity.Variable)
|
||||||
|
|
||||||
|
sourceType, ok := this.reduceToBase(source.Type()).(*entity.TypeStruct)
|
||||||
|
if !ok {
|
||||||
|
return nil, participle.Errorf (
|
||||||
|
access.Pos, "cannot access members of %v", source)
|
||||||
|
}
|
||||||
|
|
||||||
|
member, ok := sourceType.MemberMap[access.Member]
|
||||||
|
if !ok {
|
||||||
|
return nil, participle.Errorf (
|
||||||
|
access.Pos, "no member %v", access)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = this.canAssign(access.Pos, into, mode, member.Type())
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
access.Ty = into
|
||||||
|
return access, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Tree) analyzeIfElse (
|
||||||
|
into entity.Type,
|
||||||
|
mode strictness,
|
||||||
|
ifelse *entity.IfElse,
|
||||||
|
) (
|
||||||
|
entity.Expression,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
condition, err := this.analyzeExpression (
|
||||||
|
&entity.TypeBool { },
|
||||||
|
weak, ifelse.Condition)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
ifelse.Condition = condition
|
||||||
|
|
||||||
|
trueBranch, err := this.analyzeExpression(into, strict, ifelse.True)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
ifelse.True = trueBranch
|
||||||
|
|
||||||
|
if ifelse.False == nil {
|
||||||
|
if into != nil {
|
||||||
|
return nil, participle.Errorf (
|
||||||
|
ifelse.Pos,
|
||||||
|
"else case required when using value of if ")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
falseBranch, err := this.analyzeExpression(into, strict, ifelse.False)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
ifelse.False = falseBranch
|
||||||
|
}
|
||||||
|
|
||||||
|
ifelse.Ty = into
|
||||||
|
return ifelse, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Tree) analyzeLoop (
|
||||||
|
into entity.Type,
|
||||||
|
mode strictness,
|
||||||
|
loop *entity.Loop,
|
||||||
|
) (
|
||||||
|
entity.Expression,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
loop.Ty = into
|
||||||
|
|
||||||
|
body, err := this.analyzeExpression(nil, strict, loop.Body)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
loop.Body = body
|
||||||
|
|
||||||
|
return loop, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user