Skip to content

Commit

Permalink
Added types generation
Browse files Browse the repository at this point in the history
  • Loading branch information
RealA10N committed Nov 17, 2024
1 parent 78e0b48 commit 481ab3f
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 6 deletions.
37 changes: 31 additions & 6 deletions gen/info.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package gen

import "alon.kr/x/usm/core"
import (
"alon.kr/x/usm/core"
)

// MARK: Info Types

Expand All @@ -13,24 +15,47 @@ type RegisterInfo struct {
// The name of the register, as it appears in the source code.
Name core.UnmanagedSourceView

// data oriented design: This is an index into the type table, of the type
// of the register.
TypeIndex core.UsmUint
// A pointer to the TypeInfo instance that corresponds to the type of the
// register.
Type *TypeInfo
}

type ArchInfo struct {
PointerSize core.UsmUint // The size of a pointer in bytes.
}

// MARK: Managers

type TypeManager interface {
// Query a already seen before type, and get the type information if it
// exists. Returns nil if the if a type with the provided name has not yet
// been defined.
//
// The implementation should also return information about builtin types,
// although the creation of such types can be possibly done lazily.
GetType(name string) *TypeInfo

// Register a new type with the provided name and type information.
// The generator will call this method when it encounters a new type
// definition.
//
// The implementation should raise an error if the new registered type is
// invalid, for example if there already exists a type with the same name,
// or if its a builtin type.
RegisterType(name string, typ *TypeInfo) core.UsmError
}

// MARK: Generation Context

// A context object that is initialized empty, but gets propagated and filled
// with information as the code generation process continues, while iterating
// over the AST nodes.
type GenerationContext struct {
ArchInfo
core.SourceContext

Types []TypeInfo
Registers []RegisterInfo
Types TypeManager
// TODO: add registers info.

// TODO: add globals, functions, etc.
}
129 changes: 129 additions & 0 deletions gen/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Converts AST nodes representing types (type declarations, etc.) into
// types metadata (calculating type structures, type sizes, etc.).

package gen

import (
"alon.kr/x/usm/core"
"alon.kr/x/usm/parse"
)

// Valid type decorators should match the regex ".\d*" where the first rune is
// the decorator identifier (pointer, repeat, etc.), and immediately follows
// the an optional decimal number that is interpreted differently depending on
// decorator.
//
// This function parses the decorator string, and returns the decorator number,
// or an error if the decorator does not match the expected format. If a number
// is not provided, the default number is 1.
//
// Why don't we do this at the `parse` module? because the `parse` module parses
// the structure of tokens only, and does not look inside the content of the
// tokens. More specifically, it does not have access to the source context.
func ParseDecoratorNum(
genCtx *GenerationContext,
dec parse.TypeDecoratorNode,
) (core.UsmUint, core.UsmError) {
if dec.Len() <= 1 {
return 1, nil
}

numView := dec.Subview(1, dec.Len()-1)
num, err := core.ParseUint(string(numView.Raw(genCtx.SourceContext)))

if err != nil {
return 0, core.GenericError{
ErrorMessage: "Failed to parse number in type decorator",
HintMessage: "Should be a positive, decimal number",
ErrorLocation: numView,
}
}

return num, nil
}

func CalculateTypeSizeFromTypeDecorators(
genCtx *GenerationContext,
baseTypeSize core.UsmUint,
decorators []parse.TypeDecoratorNode,
) (core.UsmUint, core.UsmError) {
if len(decorators) == 0 {
return baseTypeSize, nil
}

topDecorator := decorators[len(decorators)-1]
switch topDecorator.Type {

case parse.PointerTypeDecorator:
return genCtx.PointerSize, nil

case parse.RepeatTypeDecorator:
repeatNum, err := ParseDecoratorNum(genCtx, topDecorator)
if err != nil {
return 0, err
}

// TODO: optimization: iterative and not recursive
return CalculateTypeSizeFromTypeDecorators(
genCtx,
repeatNum*baseTypeSize,
decorators[:len(decorators)-1],
)

default:
return 0, core.GenericError{
ErrorMessage: "Unknown type decorator",
ErrorLocation: topDecorator.UnmanagedSourceView,
IsInternal: true,
}
}
}

func CalculateTypeSizeFromTypeNode(
genCtx *GenerationContext,
node parse.TypeNode,
) (core.UsmUint, core.UsmError) {
typeName := string(node.Identifier.Raw(genCtx.SourceContext))
typeInfo := genCtx.Types.GetType(typeName)

if typeInfo == nil {
return 0, core.GenericError{
ErrorMessage: "Undeclared type",
ErrorLocation: node.Identifier,
}
}

return CalculateTypeSizeFromTypeDecorators(
genCtx,
typeInfo.Size,
node.Decorators,
)
}

func CalculateTypeSizeFromTypeDeclaration(
genCtx *GenerationContext,
node parse.TypeDeclarationNode,
) (size core.UsmUint, err core.UsmError) {
for _, node := range node.Fields.Nodes {
var cur core.UsmUint
cur, err = CalculateTypeSizeFromTypeNode(genCtx, node.Type)
if err != nil {
return
}
size += cur // TODO: possible int overflow?
}

return
}

// Converts an AST node representing a type declaration into a TypeInfo instance.
func TypeInfoFromTypeDeclaration(
genCtx *GenerationContext,
node parse.TypeDeclarationNode,
) (TypeInfo, core.UsmError) {
size, err := CalculateTypeSizeFromTypeDeclaration(genCtx, node)
return TypeInfo{
Name: node.Identifier,
Size: size,
}, err
}

0 comments on commit 481ab3f

Please sign in to comment.