The buge (#47) is vanquished!!!!

This commit is contained in:
Sasha Koshka 2024-02-28 19:30:33 -05:00
parent 81c4f1e46b
commit e2d944d534
1 changed files with 58 additions and 36 deletions

View File

@ -417,6 +417,14 @@ func (this *Tree) analyzeOperation (
err := this.typeRestricted(operation.Position, into)
if err != nil { return nil, err }
intoUntrustworthy := into == nil || mode == force || mode == coerce
undefined := func (ty entity.Type) (entity.Expression, error) {
return nil, errors.Errorf (
operation.Position, "operator %v undefined for %v",
operation.Operator, entity.FormatType(ty))
}
wrongInto := func () (entity.Expression, error) {
return nil, errors.Errorf (
operation.Position, "expected %v",
@ -428,6 +436,28 @@ func (this *Tree) analyzeOperation (
operation.Position, "wrong argument count for %v",
operation.Operator)
}
determineArgumentType := func () (entity.Type, int, error) {
// find the first argument that has explicit type information.
boss := -1
var argumentType entity.Type
for index, argument := range operation.Arguments {
if argument.HasExplicitType() {
argument, err := this.analyzeExpression(nil, strict, argument)
if err != nil { return nil, -1, err }
boss = index
operation.Arguments[index] = argument
argumentType = argument.Type()
break
}
}
if argumentType == nil {
return nil, -1, errors.Errorf (
operation.Position,
"operation arguments have ambiguous type")
}
return argumentType, boss, err
}
nSameType := func (n int, constraint func (entity.Type) bool) (entity.Expression, error) {
if n > 0 {
@ -436,17 +466,29 @@ func (this *Tree) analyzeOperation (
if len(operation.Arguments) < 1 { return wrongArgCount() }
}
n = len(operation.Arguments)
if !constraint(into) { return wrongInto() }
left, err := this.analyzeExpression(into, mode, operation.Arguments[0])
if err != nil { return nil, err }
operation.Arguments[0] = left
operation.Ty = left.Type()
boss := -1
var argumentType entity.Type
if intoUntrustworthy {
// determine the type of all arguments (and the return
// type) using determineArgumentType
var err error
argumentType, boss, err = determineArgumentType()
if err != nil { return nil, err }
if !constraint(argumentType) { return undefined(argumentType) }
} else {
// into is trustworthy, so we don't need to determine
// anything
argumentType = into
}
if !constraint(argumentType) { return undefined(argumentType) }
operation.Ty = argumentType
for index := 1; index < n; index ++ {
for index, argument := range operation.Arguments {
if index == boss { continue }
argument, err := this.analyzeExpression (
left.Type(), strict,
operation.Arguments[index])
operation.Ty, strict,
argument)
if err != nil { return nil, err }
operation.Arguments[index] = argument
}
@ -455,41 +497,21 @@ func (this *Tree) analyzeOperation (
}
comparison := func (argConstraint func (entity.Type) bool) (entity.Expression, error) {
if len(operation.Arguments) < 2 { return wrongArgCount() }
if !isBoolean(into) { return wrongInto() }
operation.Ty = builtinType("Bool")
if len(operation.Arguments) < 2 { return wrongArgCount() }
if !isBoolean(into) && !intoUntrustworthy { return wrongInto() }
operation.Ty = builtinType("Bool")
// 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, errors.Errorf (
operation.Position,
"operation arguments have ambiguous type")
}
// determine argument type
argumentType, boss, err := determineArgumentType()
if err != nil { return nil, err }
if !argConstraint(argumentType) { return undefined(argumentType) }
// 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
}
if err != nil { return nil, err }
operation.Arguments[index] = argument
}