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))
|
||||
case *entity.Operation:
|
||||
return this.analyzeOperation(into, mode, expression.(*entity.Operation))
|
||||
// case *entity.Block:
|
||||
// return this.analyzeBlock(into, mode, expression.(*entity.Block))
|
||||
// case *entity.MemberAccess:
|
||||
// return this.analyzeMemberAccess(into, mode, expression.(*entity.MemberAccess))
|
||||
// case *entity.IfElse:
|
||||
// return this.analyzeIfElse(into, mode, expression.(*entity.IfElse))
|
||||
// case *entity.Loop:
|
||||
// return this.analyzeLoop(into, mode, expression.(*entity.Loop))
|
||||
case *entity.Block:
|
||||
return this.analyzeBlock(into, mode, expression.(*entity.Block))
|
||||
case *entity.MemberAccess:
|
||||
return this.analyzeMemberAccess(into, mode, expression.(*entity.MemberAccess))
|
||||
case *entity.IfElse:
|
||||
return this.analyzeIfElse(into, mode, expression.(*entity.IfElse))
|
||||
case *entity.Loop:
|
||||
return this.analyzeLoop(into, mode, expression.(*entity.Loop))
|
||||
// case *entity.Break:
|
||||
// return this.analyzeBreak(into, mode, expression.(*entity.Break))
|
||||
// case *entity.Return:
|
||||
|
|
|
@ -17,7 +17,7 @@ func (this *Tree) analyzeVariable (
|
|||
entity.Expression,
|
||||
error,
|
||||
) {
|
||||
declaration := this.Variable(variable.Name)
|
||||
declaration := this.variable(variable.Name)
|
||||
if declaration == nil {
|
||||
return nil, participle.Errorf (
|
||||
variable.Pos, "no variable named %s",
|
||||
|
@ -39,7 +39,7 @@ func (this *Tree) analyzeDeclaration (
|
|||
entity.Expression,
|
||||
error,
|
||||
) {
|
||||
existing := this.TopScope().Variable(declaration.Name)
|
||||
existing := this.topScope().Variable(declaration.Name)
|
||||
if existing != nil {
|
||||
return nil, participle.Errorf (
|
||||
declaration.Pos,
|
||||
|
@ -54,7 +54,7 @@ func (this *Tree) analyzeDeclaration (
|
|||
err = this.canAssign(declaration.Pos, into, mode, declaration.Type())
|
||||
if err != nil { return nil, err }
|
||||
|
||||
this.AddVariable(declaration)
|
||||
this.addVariable(declaration)
|
||||
return &entity.Variable {
|
||||
Pos: declaration.Pos,
|
||||
Name: declaration.Name,
|
||||
|
@ -348,13 +348,48 @@ func (this *Tree) analyzeOperation (
|
|||
|
||||
return operation, nil
|
||||
}
|
||||
|
||||
|
||||
comparison := func (argConstraint func (entity.Type) bool) (entity.Expression, error) {
|
||||
if len(operation.Arguments) < 2 { return wrongArgCount() }
|
||||
if !this.isBoolean(into) { return wrongInto() }
|
||||
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 {
|
||||
|
@ -419,3 +454,124 @@ func (this *Tree) analyzeOperation (
|
|||
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