syntax-tree-accessors #2
276
parser/accessors.go
Normal file
276
parser/accessors.go
Normal file
@ -0,0 +1,276 @@
|
||||
package parser
|
||||
|
||||
import "git.tebibyte.media/arf/arf/types"
|
||||
|
||||
// LookupSection looks returns the section under the give name. If the section
|
||||
// does not exist, nil is returned.
|
||||
func (tree SyntaxTree) LookupSection (name string) (section Section) {
|
||||
section = tree.sections[name]
|
||||
return
|
||||
}
|
||||
|
||||
// Sections returns an iterator for the tree's sections
|
||||
func (tree SyntaxTree) Sections () (iterator types.Iterator[Section]) {
|
||||
iterator = types.NewIterator(tree.sections)
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns the section's kind (SectionKindType).
|
||||
func (section TypeSection) Kind () (kind SectionKind) {
|
||||
kind = SectionKindType
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns the section's kind (SectionKindObjt).
|
||||
func (section ObjtSection) Kind () (kind SectionKind) {
|
||||
kind = SectionKindObjt
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns the section's kind (SectionKindEnum).
|
||||
func (section EnumSection) Kind () (kind SectionKind) {
|
||||
kind = SectionKindEnum
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns the section's kind (SectionKindFace).
|
||||
func (section FaceSection) Kind () (kind SectionKind) {
|
||||
kind = SectionKindFace
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns the section's kind (SectionKindData).
|
||||
func (section DataSection) Kind () (kind SectionKind) {
|
||||
kind = SectionKindData
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns the section's kind (SectionKindFunc).
|
||||
func (section FuncSection) Kind () (kind SectionKind) {
|
||||
kind = SectionKindFunc
|
||||
return
|
||||
}
|
||||
|
||||
// Length returns the amount of names in the identifier.
|
||||
func (identifier Identifier) Length () (length int) {
|
||||
length = len(identifier.trail)
|
||||
return
|
||||
}
|
||||
|
||||
// Item returns the name at the specified index.
|
||||
func (identifier Identifier) Item (index int) (item string) {
|
||||
item = identifier.trail[index]
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns the type's kind.
|
||||
func (what Type) Kind () (kind TypeKind) {
|
||||
kind = what.kind
|
||||
return
|
||||
}
|
||||
|
||||
// Mutable returns whether or not the type's data is mutable.
|
||||
func (what Type) Mutable () (mutable bool) {
|
||||
mutable = what.mutable
|
||||
return
|
||||
}
|
||||
|
||||
// Length returns the length of the type if the type is a fixed length array.
|
||||
// Otherwise, it just returns zero.
|
||||
func (what Type) Length () (length uint64) {
|
||||
if what.kind == TypeKindArray {
|
||||
length = what.length
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Name returns the name of the type, if it is a basic type. Otherwise, it
|
||||
// returns a zero value identifier.
|
||||
func (what Type) Name () (name Identifier) {
|
||||
if what.kind == TypeKindBasic {
|
||||
name = what.name
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Points returns the type that this type points to, or is an array of. If the
|
||||
// type is a basic type, this returns a zero value type.
|
||||
func (what Type) Points () (points Type) {
|
||||
if what.kind != TypeKindBasic {
|
||||
points = *what.points
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Values returns an iterator for the initialization values.
|
||||
func (values ObjectInitializationValues) Sections () (
|
||||
iterator types.Iterator[Argument],
|
||||
) {
|
||||
iterator = types.NewIterator(values.attributes)
|
||||
return
|
||||
}
|
||||
|
||||
// Length returns the amount of values.
|
||||
func (values ArrayInitializationValues) Length () (length int) {
|
||||
length = len(values.values)
|
||||
return
|
||||
}
|
||||
|
||||
// Item returns the value at index.
|
||||
func (values ArrayInitializationValues) Value (index int) (value Argument) {
|
||||
value = values.values[index]
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns what kind of argument it is.
|
||||
func (argument Argument) Kind () (kind ArgumentKind) {
|
||||
kind = argument.kind
|
||||
return
|
||||
}
|
||||
|
||||
// Value returns the underlying value of the argument. You can use Kind() to
|
||||
// find out what to cast this to.
|
||||
func (argument Argument) Value () (value any) {
|
||||
value = argument.value
|
||||
return
|
||||
}
|
||||
|
||||
// BitWidth returns the bit width of the object member. If it is zero, it should
|
||||
// be treated as unspecified.
|
||||
func (member ObjtMember) BitWidth () (width uint64) {
|
||||
width = member.bitWidth
|
||||
return
|
||||
}
|
||||
|
||||
// Length returns the amount of members in the section.
|
||||
func (section ObjtSection) Length () (length int) {
|
||||
length = len(section.members)
|
||||
return
|
||||
}
|
||||
|
||||
// Item returns the member at index.
|
||||
func (section ObjtSection) Item (index int) (member ObjtMember) {
|
||||
member = section.members[index]
|
||||
return
|
||||
}
|
||||
|
||||
// Length returns the amount of members in the section.
|
||||
func (section EnumSection) Length () (length int) {
|
||||
length = len(section.members)
|
||||
return
|
||||
}
|
||||
|
||||
// Item returns the member at index.
|
||||
func (section EnumSection) Item (index int) (member EnumMember) {
|
||||
member = section.members[index]
|
||||
return
|
||||
}
|
||||
|
||||
// InputsLength returns the amount of inputs in the behavior.
|
||||
func (behavior FaceBehavior) IntputsLength () (length int) {
|
||||
length = len(behavior.inputs)
|
||||
return
|
||||
}
|
||||
|
||||
// Input returns the input at index.
|
||||
func (behavior FaceBehavior) Input (index int) (input Declaration) {
|
||||
input = behavior.inputs[index]
|
||||
return
|
||||
}
|
||||
|
||||
// OutputsLength returns the amount of outputs in the behavior.
|
||||
func (behavior FaceBehavior) OutputsLength () (length int) {
|
||||
length = len(behavior.outputs)
|
||||
return
|
||||
}
|
||||
|
||||
// Output returns the output at index.
|
||||
func (behavior FaceBehavior) Output (index int) (output Declaration) {
|
||||
output = behavior.outputs[index]
|
||||
return
|
||||
}
|
||||
|
||||
// Behaviors returns an iterator for the interface's behaviors.
|
||||
func (section FaceSection) Behaviors () (iterator types.Iterator[FaceBehavior]) {
|
||||
iterator = types.NewIterator(section.behaviors)
|
||||
return
|
||||
}
|
||||
|
||||
// Kind returns what kind of phrase it is.
|
||||
func (phrase Phrase) Kind () (kind PhraseKind) {
|
||||
kind = phrase.kind
|
||||
return
|
||||
}
|
||||
|
||||
// ArgumentsLength returns the amount of arguments in the phrase.
|
||||
func (phrase Phrase) ArgumentsLength () (length int) {
|
||||
length = len(phrase.arguments)
|
||||
return
|
||||
}
|
||||
|
||||
// Argument returns the argument at index.
|
||||
func (phrase Phrase) Argument (index int) (argument Argument) {
|
||||
argument = phrase.arguments[index]
|
||||
return
|
||||
}
|
||||
|
||||
// ReturnsToLength returns the amount of things the phrase returns to.
|
||||
func (phrase Phrase) ReturnsToLength () (length int) {
|
||||
length = len(phrase.returnsTo)
|
||||
return
|
||||
}
|
||||
|
||||
// ReturnTo returns the thing alskdjaslkdjsa whatever i dont even know wtf.
|
||||
func (phrase Phrase) ReturnTo (index int) (returnTo Argument) {
|
||||
returnTo = phrase.returnsTo[index]
|
||||
return
|
||||
}
|
||||
|
||||
// Block returns the block under the phrase, if it is a control flow statement.
|
||||
func (phrase Phrase) Block () (block Block) {
|
||||
block = phrase.block
|
||||
return
|
||||
}
|
||||
|
||||
// Receiver returns the method receiver, if there is one. Otherwise, it returns
|
||||
// nil.
|
||||
func (section FuncSection) Receiver () (receiver *Declaration) {
|
||||
receiver = section.receiver
|
||||
return
|
||||
}
|
||||
|
||||
// InputsLength returns the number of inputs in the function.
|
||||
func (section FuncSection) InputsLength () (length int) {
|
||||
length = len(section.inputs)
|
||||
return
|
||||
}
|
||||
|
||||
// Input returns the input at index.
|
||||
func (section FuncSection) Input (index int) (input Declaration) {
|
||||
input = section.inputs[index]
|
||||
return
|
||||
}
|
||||
|
||||
// OutputsLength returns the number of outputs in the function.
|
||||
func (section FuncSection) OutputsLength () (length int) {
|
||||
length = len(section.outputs)
|
||||
return
|
||||
}
|
||||
|
||||
// Output returns the output at index.
|
||||
func (section FuncSection) Output (index int) (output FuncOutput) {
|
||||
output = section.outputs[index]
|
||||
return
|
||||
}
|
||||
|
||||
// Root returns the root block of the section.
|
||||
func (section FuncSection) Root () (root Block) {
|
||||
root = section.root
|
||||
return
|
||||
}
|
||||
|
||||
// External returns whether or not the function is an external function or not.
|
||||
func (section FuncSection) External () (external bool) {
|
||||
external = section.external
|
||||
return
|
||||
}
|
@ -42,12 +42,14 @@ func (parser *ParsingOperation) parseArgument () (argument Argument, err error)
|
||||
return
|
||||
}
|
||||
|
||||
declaration := Declaration { }
|
||||
declaration.what = what
|
||||
declaration.name = identifier.trail[0]
|
||||
declaration.location = argument.Location()
|
||||
|
||||
argument.kind = ArgumentKindDeclaration
|
||||
argument.value = Declaration {
|
||||
location: argument.location,
|
||||
name: identifier.trail[0],
|
||||
what: what,
|
||||
}
|
||||
argument.value = declaration
|
||||
|
||||
} else {
|
||||
argument.kind = ArgumentKindIdentifier
|
||||
argument.value = identifier
|
||||
|
@ -8,63 +8,45 @@ func (parser *ParsingOperation) parseBody () (err error) {
|
||||
for {
|
||||
err = parser.expect(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
|
||||
sectionType := parser.token.Value().(string)
|
||||
|
||||
switch sectionType {
|
||||
case "data":
|
||||
var section *DataSection
|
||||
section, err = parser.parseDataSection()
|
||||
if parser.tree.dataSections == nil {
|
||||
parser.tree.dataSections =
|
||||
make(map[string] *DataSection)
|
||||
}
|
||||
parser.tree.dataSections[section.name] = section
|
||||
if err != nil { return }
|
||||
section, parseErr := parser.parseDataSection()
|
||||
err = parser.tree.addSection(section)
|
||||
if err != nil { return }
|
||||
if parseErr != nil { return }
|
||||
|
||||
case "type":
|
||||
var section *TypeSection
|
||||
section, err = parser.parseTypeSection()
|
||||
if parser.tree.typeSections == nil {
|
||||
parser.tree.typeSections =
|
||||
make(map[string] *TypeSection)
|
||||
}
|
||||
parser.tree.typeSections[section.name] = section
|
||||
if err != nil { return }
|
||||
section, parseErr := parser.parseTypeSection()
|
||||
err = parser.tree.addSection(section)
|
||||
if err != nil { return }
|
||||
if parseErr != nil { return }
|
||||
|
||||
case "objt":
|
||||
var section *ObjtSection
|
||||
section, err = parser.parseObjtSection()
|
||||
if parser.tree.objtSections == nil {
|
||||
parser.tree.objtSections =
|
||||
make(map[string] *ObjtSection)
|
||||
}
|
||||
parser.tree.objtSections[section.name] = section
|
||||
if err != nil { return }
|
||||
section, parseErr := parser.parseObjtSection()
|
||||
err = parser.tree.addSection(section)
|
||||
if err != nil { return }
|
||||
if parseErr != nil { return }
|
||||
|
||||
case "face":
|
||||
var section *FaceSection
|
||||
section, err = parser.parseFaceSection()
|
||||
if parser.tree.faceSections == nil {
|
||||
parser.tree.faceSections =
|
||||
make(map[string] *FaceSection)
|
||||
}
|
||||
parser.tree.faceSections[section.name] = section
|
||||
if err != nil { return }
|
||||
section, parseErr := parser.parseFaceSection()
|
||||
err = parser.tree.addSection(section)
|
||||
if err != nil { return }
|
||||
if parseErr != nil { return }
|
||||
|
||||
case "enum":
|
||||
var section *EnumSection
|
||||
section, err = parser.parseEnumSection()
|
||||
if parser.tree.enumSections == nil {
|
||||
parser.tree.enumSections =
|
||||
make(map[string] *EnumSection)
|
||||
}
|
||||
parser.tree.enumSections[section.name] = section
|
||||
if err != nil { return }
|
||||
section, parseErr := parser.parseEnumSection()
|
||||
err = parser.tree.addSection(section)
|
||||
if err != nil { return }
|
||||
if parseErr != nil { return }
|
||||
|
||||
case "func":
|
||||
var section *FuncSection
|
||||
section, err = parser.parseFuncSection()
|
||||
if parser.tree.funcSections == nil {
|
||||
parser.tree.funcSections =
|
||||
make(map[string] *FuncSection)
|
||||
}
|
||||
parser.tree.funcSections[section.name] = section
|
||||
if err != nil { return }
|
||||
section, parseErr := parser.parseFuncSection()
|
||||
err = parser.tree.addSection(section)
|
||||
if err != nil { return }
|
||||
if parseErr != nil { return }
|
||||
|
||||
default:
|
||||
err = parser.token.NewError (
|
||||
"unknown section type \"" + sectionType + "\"",
|
||||
@ -73,3 +55,18 @@ func (parser *ParsingOperation) parseBody () (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// addSection adds a section to the tree, ensuring it has a unique name within
|
||||
// the module.
|
||||
func (tree *SyntaxTree) addSection (section Section) (err error) {
|
||||
_, exists := tree.sections[section.Name()]
|
||||
if exists {
|
||||
err = section.NewError (
|
||||
"cannot have multiple sections with the same name",
|
||||
infoerr.ErrorKindError)
|
||||
return
|
||||
}
|
||||
|
||||
tree.sections[section.Name()] = section
|
||||
return
|
||||
}
|
||||
|
@ -5,13 +5,13 @@ import "git.tebibyte.media/arf/arf/lexer"
|
||||
|
||||
// parseData parses a data section.
|
||||
func (parser *ParsingOperation) parseDataSection () (
|
||||
section *DataSection,
|
||||
section DataSection,
|
||||
err error,
|
||||
) {
|
||||
err = parser.expect(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
|
||||
section = &DataSection { location: parser.token.Location() }
|
||||
section.location = parser.token.Location()
|
||||
|
||||
err = parser.nextToken(lexer.TokenKindPermission)
|
||||
if err != nil { return }
|
||||
|
@ -4,14 +4,15 @@ import "git.tebibyte.media/arf/arf/types"
|
||||
import "git.tebibyte.media/arf/arf/lexer"
|
||||
import "git.tebibyte.media/arf/arf/infoerr"
|
||||
|
||||
// parseEnumSection parses an enumerated type section.
|
||||
func (parser *ParsingOperation) parseEnumSection () (
|
||||
section *EnumSection,
|
||||
section EnumSection,
|
||||
err error,
|
||||
) {
|
||||
err = parser.expect(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
|
||||
section = &EnumSection { location: parser.token.Location() }
|
||||
section.location = parser.token.Location()
|
||||
|
||||
// get permission
|
||||
err = parser.nextToken(lexer.TokenKindPermission)
|
||||
@ -36,7 +37,7 @@ func (parser *ParsingOperation) parseEnumSection () (
|
||||
if err != nil { return }
|
||||
|
||||
// parse members
|
||||
err = parser.parseEnumMembers(section)
|
||||
err = parser.parseEnumMembers(§ion)
|
||||
if err != nil { return }
|
||||
|
||||
if len(section.members) == 0 {
|
||||
|
@ -6,16 +6,14 @@ import "git.tebibyte.media/arf/arf/infoerr"
|
||||
|
||||
// parseFaceSection parses an interface section.
|
||||
func (parser *ParsingOperation) parseFaceSection () (
|
||||
section *FaceSection,
|
||||
section FaceSection,
|
||||
err error,
|
||||
) {
|
||||
err = parser.expect(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
|
||||
section = &FaceSection {
|
||||
location: parser.token.Location(),
|
||||
behaviors: make(map[string] FaceBehavior),
|
||||
}
|
||||
section.behaviors = make(map[string] FaceBehavior)
|
||||
section.location = parser.token.Location()
|
||||
|
||||
// get permission
|
||||
err = parser.nextToken(lexer.TokenKindPermission)
|
||||
|
@ -6,13 +6,13 @@ import "git.tebibyte.media/arf/arf/infoerr"
|
||||
|
||||
// parseFunc parses a function section.
|
||||
func (parser *ParsingOperation) parseFuncSection () (
|
||||
section *FuncSection,
|
||||
section FuncSection,
|
||||
err error,
|
||||
) {
|
||||
err = parser.expect(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
|
||||
section = &FuncSection { location: parser.token.Location() }
|
||||
section.location = parser.token.Location()
|
||||
|
||||
// get permission
|
||||
err = parser.nextToken(lexer.TokenKindPermission)
|
||||
@ -29,7 +29,7 @@ func (parser *ParsingOperation) parseFuncSection () (
|
||||
if err != nil { return }
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
err = parser.parseFuncArguments(section)
|
||||
err = parser.parseFuncArguments(§ion)
|
||||
if err != nil { return }
|
||||
|
||||
// check to see if the function is external
|
||||
@ -185,12 +185,12 @@ func (parser *ParsingOperation) parseFuncArguments (
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
|
||||
output.defaultValue, err =
|
||||
output.value, err =
|
||||
parser.parseInitializationValues(1)
|
||||
into.outputs = append(into.outputs, output)
|
||||
if err != nil { return }
|
||||
} else {
|
||||
output.defaultValue, err =
|
||||
output.value, err =
|
||||
parser.parseArgument()
|
||||
into.outputs = append(into.outputs, output)
|
||||
if err != nil { return }
|
||||
|
@ -3,6 +3,29 @@ package parser
|
||||
import "git.tebibyte.media/arf/arf/lexer"
|
||||
import "git.tebibyte.media/arf/arf/infoerr"
|
||||
|
||||
// TODO: need to come up with another syntax for bitfields, and use that syntax
|
||||
// for fixed-length arrays. the problem is, we cant use {} for those kinds of
|
||||
// arrays because they aren't pointers under the hood and that goes against the
|
||||
// arf design goals in a nasty ugly way, and not only that. but the :mut type
|
||||
// qualifier is meaningless on fixed length arrays now. the bit field syntax
|
||||
// solves both of these problems very gracefully. but now, the problem is coming
|
||||
// up with new bit field syntax. implementing this change is extremely
|
||||
// necessary, for it will supercharge the coherency of the language and make it
|
||||
// way more awesome.
|
||||
//
|
||||
// this new syntax cannot conflict with arguments, so it cannot have any
|
||||
// tokens that begin those. basically all symbol tokens are on the table here.
|
||||
// some ideas:
|
||||
//
|
||||
// ro member:Type ~ 4
|
||||
// ro member:Type & 4 <- i like this one because binary &. so intuitive.
|
||||
// ro member:Type % 4
|
||||
// ro member:Type | 4
|
||||
// ro member:Type ! 4
|
||||
// ro member:Type (4) <- this looks phenomenal, but it needs new tokens not
|
||||
// used anywhere else, and it would be mildly annoying
|
||||
// to parse.
|
||||
|
||||
// parseType parses a type notation of the form Name, {Name}, etc.
|
||||
func (parser *ParsingOperation) parseType () (what Type, err error) {
|
||||
err = parser.expect(lexer.TokenKindName, lexer.TokenKindLBrace)
|
||||
@ -34,7 +57,7 @@ func (parser *ParsingOperation) parseType () (what Type, err error) {
|
||||
err = parser.nextToken(lexer.TokenKindRBrace)
|
||||
if err != nil { return }
|
||||
} else if parser.token.Is(lexer.TokenKindElipsis) {
|
||||
what.kind = TypeKindArray
|
||||
what.kind = TypeKindVariableArray
|
||||
|
||||
err = parser.nextToken(lexer.TokenKindRBrace)
|
||||
if err != nil { return }
|
||||
|
70
parser/node-traits.go
Normal file
70
parser/node-traits.go
Normal file
@ -0,0 +1,70 @@
|
||||
package parser
|
||||
|
||||
import "git.tebibyte.media/arf/arf/file"
|
||||
import "git.tebibyte.media/arf/arf/types"
|
||||
import "git.tebibyte.media/arf/arf/infoerr"
|
||||
|
||||
// locatable allows a tree node to have a location.
|
||||
type locatable struct {
|
||||
location file.Location
|
||||
}
|
||||
|
||||
// Location returns the location of the node.
|
||||
func (trait locatable) Location () (location file.Location) {
|
||||
location = trait.location
|
||||
return
|
||||
}
|
||||
|
||||
// NewError creates a new error at the node's location.
|
||||
func (trait locatable) NewError (
|
||||
message string,
|
||||
kind infoerr.ErrorKind,
|
||||
) (
|
||||
err error,
|
||||
) {
|
||||
err = infoerr.NewError(trait.location, message, kind)
|
||||
return
|
||||
}
|
||||
|
||||
// nameable allows a tree node to have a name.
|
||||
type nameable struct {
|
||||
name string
|
||||
}
|
||||
|
||||
// Name returns the name of the node.
|
||||
func (trait nameable) Name () (name string) {
|
||||
name = trait.name
|
||||
return
|
||||
}
|
||||
// typeable allows a node to have a type.
|
||||
type typeable struct {
|
||||
what Type
|
||||
}
|
||||
|
||||
// Type returns the type of the node.
|
||||
func (trait typeable) Type () (what Type) {
|
||||
what = trait.what
|
||||
return
|
||||
}
|
||||
|
||||
// permissionable allows a node to have a permission.
|
||||
type permissionable struct {
|
||||
permission types.Permission
|
||||
}
|
||||
|
||||
// Permission returns the permision of the node.
|
||||
func (trait permissionable) Permission () (permission types.Permission) {
|
||||
permission = trait.permission
|
||||
return
|
||||
}
|
||||
|
||||
// valuable allows a node to have an argument value.
|
||||
type valuable struct {
|
||||
value Argument
|
||||
}
|
||||
|
||||
// Value returns the value argument of the node.
|
||||
func (trait valuable) Value () (value Argument) {
|
||||
value = trait.value
|
||||
return
|
||||
}
|
@ -7,13 +7,13 @@ import "git.tebibyte.media/arf/arf/infoerr"
|
||||
// parseObjtSection parses an object type definition. This allows for structured
|
||||
// types to be defined, and for member variables to be added and overridden.
|
||||
func (parser *ParsingOperation) parseObjtSection () (
|
||||
section *ObjtSection,
|
||||
section ObjtSection,
|
||||
err error,
|
||||
) {
|
||||
err = parser.expect(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
|
||||
section = &ObjtSection { location: parser.token.Location() }
|
||||
section.location = parser.token.Location()
|
||||
|
||||
// get permission
|
||||
err = parser.nextToken(lexer.TokenKindPermission)
|
||||
@ -38,7 +38,7 @@ func (parser *ParsingOperation) parseObjtSection () (
|
||||
if err != nil { return }
|
||||
|
||||
// parse members
|
||||
err = parser.parseObjtMembers(section)
|
||||
err = parser.parseObjtMembers(§ion)
|
||||
if err != nil { return }
|
||||
|
||||
if len(section.members) == 0 {
|
||||
@ -108,11 +108,11 @@ func (parser *ParsingOperation) parseObjtMember () (
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
|
||||
member.defaultValue,
|
||||
member.value,
|
||||
err = parser.parseInitializationValues(1)
|
||||
if err != nil { return }
|
||||
} else {
|
||||
member.defaultValue, err = parser.parseArgument()
|
||||
member.value, err = parser.parseArgument()
|
||||
if err != nil { return }
|
||||
|
||||
err = parser.expect(lexer.TokenKindNewline)
|
||||
|
@ -14,13 +14,25 @@ type ParsingOperation struct {
|
||||
tokens []lexer.Token
|
||||
tokenIndex int
|
||||
|
||||
tree *SyntaxTree
|
||||
tree SyntaxTree
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// - implement parser cache
|
||||
// - have this try to hit the cache, and actually parse on miss
|
||||
// - rename this to Fetch
|
||||
// - add `skim bool` argument. when this is true, don't parse any code or data
|
||||
// section initialization values, just definitions and their default values.
|
||||
|
||||
// Parse reads the files located in the module specified by modulePath, and
|
||||
// converts them into an abstract syntax tree.
|
||||
func Parse (modulePath string) (tree *SyntaxTree, err error) {
|
||||
parser := ParsingOperation { modulePath: modulePath }
|
||||
func Parse (modulePath string) (tree SyntaxTree, err error) {
|
||||
parser := ParsingOperation {
|
||||
modulePath: modulePath,
|
||||
tree: SyntaxTree {
|
||||
sections: make(map[string] Section),
|
||||
},
|
||||
}
|
||||
|
||||
if parser.modulePath[len(parser.modulePath) - 1] != '/' {
|
||||
parser.modulePath += "/"
|
||||
@ -54,9 +66,6 @@ func (parser *ParsingOperation) parse (sourceFile *file.File) (err error) {
|
||||
if err != nil { return }
|
||||
|
||||
// reset the parser
|
||||
if parser.tree == nil {
|
||||
parser.tree = &SyntaxTree { }
|
||||
}
|
||||
if len(tokens) == 0 { return }
|
||||
parser.tokens = tokens
|
||||
parser.token = tokens[0]
|
||||
|
@ -7,15 +7,6 @@ import "testing"
|
||||
|
||||
func checkTree (modulePath string, correct string, test *testing.T) {
|
||||
tree, err := Parse(modulePath)
|
||||
if tree == nil {
|
||||
test.Log("TREE IS NIL!")
|
||||
if err != io.EOF && err != nil {
|
||||
test.Log("returned error:")
|
||||
test.Log(err)
|
||||
}
|
||||
test.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
treeString := tree.ToString(0)
|
||||
treeRunes := []rune(treeString)
|
||||
|
@ -30,7 +30,7 @@ func sortMapKeysAlphabetically[KEY_TYPE any] (
|
||||
return
|
||||
}
|
||||
|
||||
func (tree *SyntaxTree) ToString (indent int) (output string) {
|
||||
func (tree SyntaxTree) ToString (indent int) (output string) {
|
||||
output += doIndent(indent, ":arf\n")
|
||||
|
||||
if tree.author != "" {
|
||||
@ -47,35 +47,11 @@ func (tree *SyntaxTree) ToString (indent int) (output string) {
|
||||
|
||||
output += doIndent(indent, "---\n")
|
||||
|
||||
typeSectionKeys := sortMapKeysAlphabetically(tree.typeSections)
|
||||
for _, name := range typeSectionKeys {
|
||||
output += tree.typeSections[name].ToString(indent)
|
||||
sectionKeys := sortMapKeysAlphabetically(tree.sections)
|
||||
for _, name := range sectionKeys {
|
||||
output += tree.sections[name].ToString(indent)
|
||||
}
|
||||
|
||||
objtSectionKeys := sortMapKeysAlphabetically(tree.objtSections)
|
||||
for _, name := range objtSectionKeys {
|
||||
output += tree.objtSections[name].ToString(indent)
|
||||
}
|
||||
|
||||
enumSectionKeys := sortMapKeysAlphabetically(tree.enumSections)
|
||||
for _, name := range enumSectionKeys {
|
||||
output += tree.enumSections[name].ToString(indent)
|
||||
}
|
||||
|
||||
faceSectionKeys := sortMapKeysAlphabetically(tree.faceSections)
|
||||
for _, name := range faceSectionKeys {
|
||||
output += tree.faceSections[name].ToString(indent)
|
||||
}
|
||||
|
||||
dataSectionKeys := sortMapKeysAlphabetically(tree.dataSections)
|
||||
for _, name := range dataSectionKeys {
|
||||
output += tree.dataSections[name].ToString(indent)
|
||||
}
|
||||
|
||||
funcSectionKeys := sortMapKeysAlphabetically(tree.funcSections)
|
||||
for _, name := range funcSectionKeys {
|
||||
output += tree.funcSections[name].ToString(indent)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -90,7 +66,7 @@ func (identifier Identifier) ToString () (output string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (what *Type) ToString () (output string) {
|
||||
func (what Type) ToString () (output string) {
|
||||
if what.kind == TypeKindBasic {
|
||||
output += what.name.ToString()
|
||||
} else {
|
||||
@ -98,12 +74,9 @@ func (what *Type) ToString () (output string) {
|
||||
output += what.points.ToString()
|
||||
|
||||
if what.kind == TypeKindArray {
|
||||
output += " "
|
||||
if what.length == 0 {
|
||||
output += ".."
|
||||
} else {
|
||||
output += fmt.Sprint(what.length)
|
||||
}
|
||||
output += fmt.Sprint(" ", what.length)
|
||||
} else if what.kind == TypeKindVariableArray {
|
||||
output += " .."
|
||||
}
|
||||
|
||||
output += "}"
|
||||
@ -154,7 +127,7 @@ func (values ArrayInitializationValues) ToString (
|
||||
return
|
||||
}
|
||||
|
||||
func (argument *Argument) ToString (indent int, breakLine bool) (output string) {
|
||||
func (argument Argument) ToString (indent int, breakLine bool) (output string) {
|
||||
if !breakLine { indent = 0 }
|
||||
if argument.kind == ArgumentKindNil {
|
||||
output += "NIL-ARGUMENT"
|
||||
@ -279,7 +252,7 @@ func (argument *Argument) ToString (indent int, breakLine bool) (output string)
|
||||
return
|
||||
}
|
||||
|
||||
func (section *DataSection) ToString (indent int) (output string) {
|
||||
func (section DataSection) ToString (indent int) (output string) {
|
||||
output += doIndent (
|
||||
indent,
|
||||
"data ",
|
||||
@ -303,25 +276,25 @@ func (section *DataSection) ToString (indent int) (output string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (section *TypeSection) ToString (indent int) (output string) {
|
||||
func (section TypeSection) ToString (indent int) (output string) {
|
||||
output += doIndent (
|
||||
indent,
|
||||
"type ",
|
||||
section.permission.ToString(), " ",
|
||||
section.name, ":",
|
||||
section.inherits.ToString())
|
||||
section.what.ToString())
|
||||
|
||||
isComplexInitialization :=
|
||||
section.defaultValue.kind == ArgumentKindObjectInitializationValues ||
|
||||
section.defaultValue.kind == ArgumentKindArrayInitializationValues
|
||||
section.value.kind == ArgumentKindObjectInitializationValues ||
|
||||
section.value.kind == ArgumentKindArrayInitializationValues
|
||||
|
||||
if section.defaultValue.value == nil {
|
||||
if section.value.value == nil {
|
||||
output += "\n"
|
||||
} else if isComplexInitialization {
|
||||
output += "\n"
|
||||
output += section.defaultValue.ToString(indent + 1, true)
|
||||
output += section.value.ToString(indent + 1, true)
|
||||
} else {
|
||||
output += " " + section.defaultValue.ToString(0, false)
|
||||
output += " " + section.value.ToString(0, false)
|
||||
output += "\n"
|
||||
}
|
||||
return
|
||||
@ -339,23 +312,23 @@ func (member ObjtMember) ToString (indent int) (output string) {
|
||||
}
|
||||
|
||||
isComplexInitialization :=
|
||||
member.defaultValue.kind == ArgumentKindObjectInitializationValues ||
|
||||
member.defaultValue.kind == ArgumentKindArrayInitializationValues
|
||||
member.value.kind == ArgumentKindObjectInitializationValues ||
|
||||
member.value.kind == ArgumentKindArrayInitializationValues
|
||||
|
||||
if member.defaultValue.value == nil {
|
||||
if member.value.value == nil {
|
||||
output += "\n"
|
||||
} else if isComplexInitialization {
|
||||
output += "\n"
|
||||
output += member.defaultValue.ToString(indent + 1, true)
|
||||
output += member.value.ToString(indent + 1, true)
|
||||
} else {
|
||||
output += " " + member.defaultValue.ToString(0, false)
|
||||
output += " " + member.value.ToString(0, false)
|
||||
output += "\n"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (section *ObjtSection) ToString (indent int) (output string) {
|
||||
func (section ObjtSection) ToString (indent int) (output string) {
|
||||
output += doIndent (
|
||||
indent,
|
||||
"objt ",
|
||||
@ -369,7 +342,7 @@ func (section *ObjtSection) ToString (indent int) (output string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (section *EnumSection) ToString (indent int) (output string) {
|
||||
func (section EnumSection) ToString (indent int) (output string) {
|
||||
output += doIndent (
|
||||
indent,
|
||||
"enum ",
|
||||
@ -397,7 +370,7 @@ func (section *EnumSection) ToString (indent int) (output string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (section *FaceSection) ToString (indent int) (output string) {
|
||||
func (section FaceSection) ToString (indent int) (output string) {
|
||||
output += doIndent (
|
||||
indent,
|
||||
"face ",
|
||||
@ -412,7 +385,7 @@ func (section *FaceSection) ToString (indent int) (output string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (behavior *FaceBehavior) ToString (indent int) (output string) {
|
||||
func (behavior FaceBehavior) ToString (indent int) (output string) {
|
||||
output += doIndent(indent, behavior.name, "\n")
|
||||
|
||||
for _, inputItem := range behavior.inputs {
|
||||
@ -473,13 +446,13 @@ func (block Block) ToString (indent int) (output string) {
|
||||
|
||||
func (funcOutput FuncOutput) ToString () (output string) {
|
||||
output += funcOutput.Declaration.ToString()
|
||||
if funcOutput.defaultValue.kind != ArgumentKindNil {
|
||||
output += " " + funcOutput.defaultValue.ToString(0, false)
|
||||
if funcOutput.value.kind != ArgumentKindNil {
|
||||
output += " " + funcOutput.value.ToString(0, false)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (section *FuncSection) ToString (indent int) (output string) {
|
||||
func (section FuncSection) ToString (indent int) (output string) {
|
||||
output += doIndent (
|
||||
indent,
|
||||
"func ",
|
||||
|
151
parser/tree.go
151
parser/tree.go
@ -2,6 +2,7 @@ package parser
|
||||
|
||||
import "git.tebibyte.media/arf/arf/file"
|
||||
import "git.tebibyte.media/arf/arf/types"
|
||||
import "git.tebibyte.media/arf/arf/infoerr"
|
||||
|
||||
// SyntaxTree represents an abstract syntax tree. It covers an entire module. It
|
||||
// can be expected to be syntactically correct, but it might not be semantically
|
||||
@ -10,22 +11,40 @@ type SyntaxTree struct {
|
||||
license string
|
||||
author string
|
||||
|
||||
requires []string
|
||||
typeSections map[string] *TypeSection
|
||||
objtSections map[string] *ObjtSection
|
||||
enumSections map[string] *EnumSection
|
||||
faceSections map[string] *FaceSection
|
||||
dataSections map[string] *DataSection
|
||||
funcSections map[string] *FuncSection
|
||||
requires []string
|
||||
sections map[string] Section
|
||||
}
|
||||
|
||||
// Identifier represents a chain of arguments separated by a dot.
|
||||
// SectionKind differentiates Section interfaces.
|
||||
type SectionKind int
|
||||
|
||||
const (
|
||||
SectionKindType = iota
|
||||
SectionKindObjt
|
||||
SectionKindEnum
|
||||
SectionKindFace
|
||||
SectionKindData
|
||||
SectionKindFunc
|
||||
)
|
||||
|
||||
// Section can be any kind of section. You can find out what type of section it
|
||||
// is with the Kind method.
|
||||
type Section interface {
|
||||
Location () (location file.Location)
|
||||
Kind () (kind SectionKind)
|
||||
Permission () (permission types.Permission)
|
||||
Name () (name string)
|
||||
NewError (message string, kind infoerr.ErrorKind) (err error)
|
||||
ToString (indent int) (output string)
|
||||
}
|
||||
|
||||
// Identifier represents a chain of names separated by a dot.
|
||||
type Identifier struct {
|
||||
location file.Location
|
||||
trail []string
|
||||
locatable
|
||||
trail []string
|
||||
}
|
||||
|
||||
// TypeKind represents what kind of type a type is
|
||||
// TypeKind represents what kind of type a type is.
|
||||
type TypeKind int
|
||||
|
||||
const (
|
||||
@ -36,19 +55,21 @@ const (
|
||||
// TypeKindPointer means it's a pointer
|
||||
TypeKindPointer
|
||||
|
||||
// TypeKindArray means it's an array.
|
||||
// TypeKindArray means it's a fixed length array.
|
||||
TypeKindArray
|
||||
|
||||
// TypeKindVariableArray means it's an array of variable length.
|
||||
TypeKindVariableArray
|
||||
)
|
||||
|
||||
// Type represents a type specifier
|
||||
type Type struct {
|
||||
location file.Location
|
||||
locatable
|
||||
|
||||
mutable bool
|
||||
kind TypeKind
|
||||
|
||||
// only applicable for arrays. a value of zero means it has an
|
||||
// undefined/dynamic length.
|
||||
// only applicable for fixed length arrays.
|
||||
length uint64
|
||||
|
||||
// only applicable for basic.
|
||||
@ -60,23 +81,23 @@ type Type struct {
|
||||
|
||||
// Declaration represents a variable declaration.
|
||||
type Declaration struct {
|
||||
location file.Location
|
||||
name string
|
||||
what Type
|
||||
locatable
|
||||
nameable
|
||||
typeable
|
||||
}
|
||||
|
||||
// ObjectInitializationValues represents a list of object member initialization
|
||||
// attributes.
|
||||
type ObjectInitializationValues struct {
|
||||
location file.Location
|
||||
locatable
|
||||
attributes map[string] Argument
|
||||
}
|
||||
|
||||
// ArrayInitializationValues represents a list of attributes initializing an
|
||||
// array.
|
||||
type ArrayInitializationValues struct {
|
||||
location file.Location
|
||||
values []Argument
|
||||
locatable
|
||||
values []Argument
|
||||
}
|
||||
|
||||
// ArgumentKind specifies the type of thing the value of an argument should be
|
||||
@ -139,75 +160,73 @@ const (
|
||||
// Argument represents a value that can be placed anywhere a value goes. This
|
||||
// allows things like phrases being arguments to other phrases.
|
||||
type Argument struct {
|
||||
location file.Location
|
||||
kind ArgumentKind
|
||||
value any
|
||||
locatable
|
||||
kind ArgumentKind
|
||||
value any
|
||||
// TODO: if there is an argument expansion operator its existence should
|
||||
// be stored here in a boolean.
|
||||
}
|
||||
|
||||
// DataSection represents a global variable.
|
||||
type DataSection struct {
|
||||
location file.Location
|
||||
name string
|
||||
|
||||
what Type
|
||||
permission types.Permission
|
||||
value Argument
|
||||
locatable
|
||||
nameable
|
||||
typeable
|
||||
permissionable
|
||||
valuable
|
||||
}
|
||||
|
||||
// TypeSection represents a blind type definition.
|
||||
type TypeSection struct {
|
||||
location file.Location
|
||||
name string
|
||||
|
||||
inherits Type
|
||||
permission types.Permission
|
||||
defaultValue Argument
|
||||
locatable
|
||||
nameable
|
||||
typeable
|
||||
permissionable
|
||||
valuable
|
||||
}
|
||||
|
||||
// ObjtMember represents a part of an object type definition.
|
||||
type ObjtMember struct {
|
||||
location file.Location
|
||||
name string
|
||||
locatable
|
||||
nameable
|
||||
typeable
|
||||
permissionable
|
||||
valuable
|
||||
|
||||
what Type
|
||||
bitWidth uint64
|
||||
permission types.Permission
|
||||
defaultValue Argument
|
||||
bitWidth uint64
|
||||
}
|
||||
|
||||
// ObjtSection represents an object type definition.
|
||||
type ObjtSection struct {
|
||||
location file.Location
|
||||
name string
|
||||
locatable
|
||||
nameable
|
||||
permissionable
|
||||
inherits Identifier
|
||||
|
||||
inherits Identifier
|
||||
permission types.Permission
|
||||
members []ObjtMember
|
||||
members []ObjtMember
|
||||
}
|
||||
|
||||
// EnumMember represents a member of an enum section.
|
||||
type EnumMember struct {
|
||||
location file.Location
|
||||
name string
|
||||
value Argument
|
||||
locatable
|
||||
nameable
|
||||
valuable
|
||||
}
|
||||
|
||||
// EnumSection represents an enumerated type section.
|
||||
type EnumSection struct {
|
||||
location file.Location
|
||||
name string
|
||||
locatable
|
||||
nameable
|
||||
typeable
|
||||
permissionable
|
||||
|
||||
what Type
|
||||
permission types.Permission
|
||||
members []EnumMember
|
||||
members []EnumMember
|
||||
}
|
||||
|
||||
// FaceBehavior represents a behavior of an interface section.
|
||||
type FaceBehavior struct {
|
||||
location file.Location
|
||||
name string
|
||||
locatable
|
||||
nameable
|
||||
|
||||
inputs []Declaration
|
||||
outputs []Declaration
|
||||
@ -215,12 +234,12 @@ type FaceBehavior struct {
|
||||
|
||||
// FaceSection represents an interface type section.
|
||||
type FaceSection struct {
|
||||
location file.Location
|
||||
name string
|
||||
locatable
|
||||
nameable
|
||||
permissionable
|
||||
inherits Identifier
|
||||
|
||||
permission types.Permission
|
||||
behaviors map[string] FaceBehavior
|
||||
behaviors map[string] FaceBehavior
|
||||
}
|
||||
|
||||
// PhraseKind determines what semantic role a phrase plays.
|
||||
@ -248,6 +267,8 @@ type Phrase struct {
|
||||
location file.Location
|
||||
command Argument
|
||||
arguments []Argument
|
||||
// TODO: this is wack. it should be named after a plural noun like,
|
||||
// returnees or something. accessor methods should beupdated to match.
|
||||
returnsTo []Argument
|
||||
|
||||
kind PhraseKind
|
||||
@ -263,14 +284,14 @@ type Block []Phrase
|
||||
// that it can have a default value.
|
||||
type FuncOutput struct {
|
||||
Declaration
|
||||
defaultValue Argument
|
||||
valuable
|
||||
}
|
||||
|
||||
// FuncSection represents a function section.
|
||||
type FuncSection struct {
|
||||
location file.Location
|
||||
name string
|
||||
permission types.Permission
|
||||
locatable
|
||||
nameable
|
||||
permissionable
|
||||
|
||||
receiver *Declaration
|
||||
inputs []Declaration
|
||||
|
@ -2,18 +2,17 @@ package parser
|
||||
|
||||
import "git.tebibyte.media/arf/arf/types"
|
||||
import "git.tebibyte.media/arf/arf/lexer"
|
||||
// import "git.tebibyte.media/arf/arf/infoerr"
|
||||
|
||||
// parseTypeSection parses a blind type definition, meaning it can inherit from
|
||||
// anything including primitives, but cannot define structure.
|
||||
func (parser *ParsingOperation) parseTypeSection () (
|
||||
section *TypeSection,
|
||||
section TypeSection,
|
||||
err error,
|
||||
) {
|
||||
err = parser.expect(lexer.TokenKindName)
|
||||
if err != nil { return }
|
||||
|
||||
section = &TypeSection { location: parser.token.Location() }
|
||||
section.location = parser.token.Location()
|
||||
|
||||
// get permission
|
||||
err = parser.nextToken(lexer.TokenKindPermission)
|
||||
@ -30,7 +29,7 @@ func (parser *ParsingOperation) parseTypeSection () (
|
||||
if err != nil { return }
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
section.inherits, err = parser.parseType()
|
||||
section.what, err = parser.parseType()
|
||||
if err != nil { return }
|
||||
|
||||
// parse default values
|
||||
@ -38,10 +37,10 @@ func (parser *ParsingOperation) parseTypeSection () (
|
||||
err = parser.nextToken()
|
||||
if err != nil { return }
|
||||
|
||||
section.defaultValue, err = parser.parseInitializationValues(0)
|
||||
section.value, err = parser.parseInitializationValues(0)
|
||||
if err != nil { return }
|
||||
} else {
|
||||
section.defaultValue, err = parser.parseArgument()
|
||||
section.value, err = parser.parseArgument()
|
||||
if err != nil { return }
|
||||
|
||||
err = parser.expect(lexer.TokenKindNewline)
|
||||
|
50
types/iterator.go
Normal file
50
types/iterator.go
Normal file
@ -0,0 +1,50 @@
|
||||
package types
|
||||
|
||||
// Iterator is an object capable of iterating over any string-indexed map, while
|
||||
// protecting its data.
|
||||
type Iterator[VALUE_TYPE any] struct {
|
||||
index int
|
||||
keys []string
|
||||
underlying map[string] VALUE_TYPE
|
||||
}
|
||||
|
||||
// NewIterator creates a new iterator that iterates over the specified map.
|
||||
func NewIterator[VALUE_TYPE any] (
|
||||
underlying map[string] VALUE_TYPE,
|
||||
) (
|
||||
iterator Iterator[VALUE_TYPE],
|
||||
) {
|
||||
iterator.underlying = underlying
|
||||
iterator.keys = make([]string, len(underlying))
|
||||
|
||||
index := 0
|
||||
for key, _ := range underlying {
|
||||
iterator.keys[index] = key
|
||||
index ++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Key returns the current key the iterator is on.
|
||||
func (iterator Iterator[VALUE_TYPE]) Key () (key string) {
|
||||
key = iterator.keys[iterator.index]
|
||||
return
|
||||
}
|
||||
|
||||
// Value returns the current value the iterator is on.
|
||||
func (iterator Iterator[VALUE_TYPE]) Value () (value VALUE_TYPE) {
|
||||
value = iterator.underlying[iterator.keys[iterator.index]]
|
||||
return
|
||||
}
|
||||
|
||||
// Next advances the iterator by 1.
|
||||
func (iterator Iterator[VALUE_TYPE]) Next () {
|
||||
iterator.index ++
|
||||
}
|
||||
|
||||
// End returns whether the iterator has reached the end of the map.
|
||||
func (iterator Iterator[VALUE_TYPE]) End () (atEnd bool) {
|
||||
atEnd = iterator.index >= len(iterator.keys) || iterator.index < 0
|
||||
return
|
||||
}
|
Reference in New Issue
Block a user