Analyze more expressions

This commit is contained in:
Sasha Koshka 2023-10-29 02:18:41 -04:00
parent 2018ccead6
commit b8d573f2cd
2 changed files with 169 additions and 13 deletions

View File

@ -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:

View File

@ -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
}