Improved type safety for memory writes

This commit is contained in:
2025-04-14 15:58:15 +02:00
parent 43a006e4af
commit 6483573923
7 changed files with 54 additions and 51 deletions

View File

@ -8,6 +8,7 @@ import (
"git.urbach.dev/cli/q/src/errors"
"git.urbach.dev/cli/q/src/eval"
"git.urbach.dev/cli/q/src/token"
"git.urbach.dev/cli/q/src/types"
)
// CompileAssign compiles an assign statement.
@ -56,11 +57,23 @@ func (f *Function) CompileAssign(node *ast.Assign) error {
return err
}
if !types.Is(rightValue.Type(), leftValue.Typ) {
return errors.New(&errors.TypeMismatch{Encountered: rightValue.Type().Name(), Expected: leftValue.Typ.Name()}, f.File, right.Token.Position)
}
leftSize := leftValue.Memory.Length
rightSize := uint8(rightValue.Type().Size())
if rightSize != 0 && leftSize != rightSize {
panic("memory store length mismatch")
switch {
case leftSize == 0:
leftSize = rightSize
leftValue.Memory.Length = rightSize
case rightSize == 0:
rightSize = leftSize
}
if leftSize == 0 {
return errors.New(errors.UnknownMemorySize, f.File, operation.Position)
}
f.ValueToMemory(rightValue, leftValue.Memory)

View File

@ -21,28 +21,27 @@ func (f *Function) EvaluateArray(expr *expression.Expression) (*eval.Memory, err
defer f.UseVariable(base)
memory := asm.Memory{
value := &eval.Memory{
Memory: asm.Memory{
Base: base.Value.Register,
Offset: 0,
OffsetRegister: -1,
Length: byte(1),
Length: 0,
},
}
if len(expr.Children) == 1 {
pointer, isPointer := base.Value.Typ.(*types.Pointer)
if !isPointer {
switch baseType := base.Value.Typ.(type) {
case *types.Array:
value.Typ = baseType.Of
value.Memory.Length = byte(baseType.Of.Size())
case *types.Pointer:
value.Typ = baseType.To
value.Memory.Length = byte(baseType.To.Size())
default:
return nil, errors.New(&errors.TypeMismatch{Encountered: base.Value.Typ.Name(), Expected: types.AnyPointer.Name()}, f.File, expr.Token.Position)
}
// TODO: This is a hack that needs to be removed
memory.Length = 8
value := &eval.Memory{
Typ: pointer.To,
Memory: memory,
}
if len(expr.Children) == 1 {
return value, nil
}
@ -59,34 +58,12 @@ func (f *Function) EvaluateArray(expr *expression.Expression) (*eval.Memory, err
switch index := index.(type) {
case *eval.Number:
memory.Offset = int8(index.Number)
value.Memory.Offset = int8(index.Number)
case *eval.Register:
memory.OffsetRegister = index.Register
value.Memory.OffsetRegister = index.Register
default:
panic(fmt.Errorf("%s: not implemented: %v", f.UniqueName, index))
}
array, isArray := base.Value.Typ.(*types.Array)
if isArray {
value := &eval.Memory{
Typ: array.Of,
Memory: memory,
}
return value, nil
}
pointer, isPointer := base.Value.Typ.(*types.Pointer)
if isPointer {
value := &eval.Memory{
Typ: pointer.To,
Memory: memory,
}
return value, nil
}
panic("invalid type")
}

View File

@ -21,5 +21,6 @@ var (
MissingParameter = &Base{"Missing parameter"}
MissingType = &Base{"Missing type"}
NotImplemented = &Base{"Not implemented"}
UnknownMemorySize = &Base{"Unknown memory size"}
UntypedExpression = &Base{"Untyped expression"}
)

View File

@ -26,8 +26,13 @@ func (s *Scanner) scanStruct(file *fs.File, tokens token.List, i int) (int, erro
fieldPosition := i
fieldName := tokens[i].Text(file.Bytes)
i++
fieldTypeName := tokens[i].Text(file.Bytes)
typePosition := i
for i < len(tokens) && tokens[i].Kind != token.NewLine && tokens[i].Kind != token.BlockEnd {
i++
}
fieldTypeName := tokens[typePosition:i].Text(file.Bytes)
structure.AddField(&types.Field{
Name: fieldName,

View File

@ -2,6 +2,6 @@ main() {
writeToMemory(42)
}
writeToMemory(p *any) {
p[0] = 'A'
writeToMemory(p *byte) {
[p] = 'A'
}

View File

@ -0,0 +1,6 @@
import mem
main() {
a := mem.alloc(1)
a[0] = int64(1)
}

View File

@ -49,11 +49,12 @@ var errs = []struct {
{"MissingParameter3.q", errors.MissingParameter},
{"MissingType.q", errors.MissingType},
{"ReturnCountMismatch.q", &errors.ReturnCountMismatch{Count: 1, ExpectedCount: 0}},
{"TypeMismatch.q", &errors.TypeMismatch{Expected: "*any", Encountered: "int", ParameterName: "p"}},
{"TypeMismatch.q", &errors.TypeMismatch{Expected: "*uint8", Encountered: "int", ParameterName: "p"}},
{"TypeMismatch2.q", &errors.TypeMismatch{Expected: "[]any", Encountered: "int", ParameterName: "array"}},
{"TypeMismatch3.q", &errors.TypeMismatch{Expected: "int", Encountered: "[]uint8"}},
{"TypeMismatch4.q", &errors.TypeMismatch{Expected: "int", Encountered: "[]uint8"}},
{"TypeMismatch5.q", &errors.TypeMismatch{Expected: "*any", Encountered: "int64"}},
{"TypeMismatch6.q", &errors.TypeMismatch{Expected: "uint8", Encountered: "int64"}},
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
{"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}},
{"UnknownIdentifier3.q", &errors.UnknownIdentifier{Name: "x"}},