diff --git a/src/compiler/Compile.go b/src/compiler/Compile.go index 226c72f..065976b 100644 --- a/src/compiler/Compile.go +++ b/src/compiler/Compile.go @@ -37,7 +37,11 @@ func Compile(build *config.Build) (*core.Environment, error) { // We couldn't do that during the scan phase because it's possible // that a field references a type that will only be known after the // full scan is finished. - parseFieldTypes(env.Structs(), env) + err = parseFieldTypes(env.Structs(), env) + + if err != nil { + return nil, err + } // Parse input and output types so we have type information // ready for all functions before parallel compilation starts. diff --git a/src/compiler/errors.go b/src/compiler/errors.go index 9643789..7fef0cb 100644 --- a/src/compiler/errors.go +++ b/src/compiler/errors.go @@ -11,6 +11,15 @@ var ( MissingMainFunction = errors.String("Missing main function") ) +// UnknownType error is created when a type could not be found. +type UnknownType struct { + Name string +} + +func (err *UnknownType) Error() string { + return fmt.Sprintf("Unknown type '%s'", err.Name) +} + // UnusedImport error is created when an import is never used. type UnusedImport struct { Package string diff --git a/src/compiler/errors_test.go b/src/compiler/errors_test.go index 62ee4cd..9a16ca0 100644 --- a/src/compiler/errors_test.go +++ b/src/compiler/errors_test.go @@ -15,6 +15,7 @@ var errs = []struct { ExpectedError error }{ {"MissingMainFunction.q", compiler.MissingMainFunction}, + {"UnknownType.q", &compiler.UnknownType{Name: "unknown"}}, {"UnusedImport.q", &compiler.UnusedImport{Package: "os"}}, } diff --git a/src/compiler/parseFieldTypes.go b/src/compiler/parseFieldTypes.go index d08b8a5..80b96e1 100644 --- a/src/compiler/parseFieldTypes.go +++ b/src/compiler/parseFieldTypes.go @@ -4,19 +4,27 @@ import ( "iter" "git.urbach.dev/cli/q/src/core" + "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/types" ) // parseFieldTypes parses the tokens of the struct field types. -func parseFieldTypes(structs iter.Seq[*types.Struct], env *core.Environment) { +func parseFieldTypes(structs iter.Seq[*types.Struct], env *core.Environment) error { for structure := range structs { offset := 0 for i, field := range structure.Fields { field.Type = core.ParseType(field.Tokens[1:], structure.File.Bytes, env) + + if field.Type == nil { + return errors.New(&UnknownType{Name: field.Tokens[1:].String(structure.File.Bytes)}, structure.File, field.Tokens[1].Position) + } + field.Index = uint8(i) field.Offset = uint8(offset) offset += field.Type.Size() } } + + return nil } \ No newline at end of file diff --git a/src/compiler/testdata/UnknownType.q b/src/compiler/testdata/UnknownType.q new file mode 100644 index 0000000..fc2eef5 --- /dev/null +++ b/src/compiler/testdata/UnknownType.q @@ -0,0 +1,6 @@ +Point { + x unknown + y unknown +} + +main() {} \ No newline at end of file diff --git a/src/scanner/scanStruct.go b/src/scanner/scanStruct.go index f7a8455..5807b6f 100644 --- a/src/scanner/scanStruct.go +++ b/src/scanner/scanStruct.go @@ -26,9 +26,8 @@ func (s *scanner) scanStruct(file *fs.File, tokens token.List, i int) (int, erro name := tokens[start].String(file.Bytes) structure.AddField(&types.Field{ - Tokens: tokens[start:i], - Name: name, - Position: token.Position(start), + Name: name, + Tokens: tokens[start:i], }) } diff --git a/src/types/Field.go b/src/types/Field.go index aae4cd7..1eced8f 100644 --- a/src/types/Field.go +++ b/src/types/Field.go @@ -4,12 +4,11 @@ import "git.urbach.dev/cli/q/src/token" // Field is a memory region in a data structure. type Field struct { - Type Type - Name string - Tokens token.List - Position token.Position - Index uint8 - Offset uint8 + Type Type + Name string + Tokens token.List + Index uint8 + Offset uint8 } // String returns the name of the struct.