Compare commits
9 Commits
5641220986
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 40f3ea743a | |||
| 4fb73a3465 | |||
| 58bae14528 | |||
| 4385319874 | |||
| e85e61d70c | |||
| e067483942 | |||
| 4929081d87 | |||
| befe371e4f | |||
| dfa7d31163 |
@@ -1,5 +1,9 @@
|
|||||||
# 
|
# 
|
||||||
|
|
||||||
|
This repository is no longer being developed. The ARF language has since gone through several revisions and has been given a different name (FSPL), and the new version can be found [here](git.tebibyte.media/fspl/fspl).
|
||||||
|
|
||||||
|
README of this repository:
|
||||||
|
|
||||||
The ARF programming language.
|
The ARF programming language.
|
||||||
|
|
||||||
This is still under development and does not compile things yet. Once complete,
|
This is still under development and does not compile things yet. Once complete,
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (analyzer *analysisOperation) analyze () (err error) {
|
|||||||
for !sections.End() {
|
for !sections.End() {
|
||||||
_, err = analyzer.fetchSection(locator {
|
_, err = analyzer.fetchSection(locator {
|
||||||
modulePath: analyzer.modulePath,
|
modulePath: analyzer.modulePath,
|
||||||
name: sections.Value().Name(),
|
name: sections.Key(),
|
||||||
})
|
})
|
||||||
if err != nil { return err }
|
if err != nil { return err }
|
||||||
sections.Next()
|
sections.Next()
|
||||||
@@ -93,7 +93,7 @@ func (analyzer *analysisOperation) fetchSection (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsedSection = tree.LookupSection(where.name)
|
var parsedSection = tree.LookupSection("", where.name)
|
||||||
if parsedSection == nil {
|
if parsedSection == nil {
|
||||||
section = nil
|
section = nil
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,5 +1,39 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
|
import "git.tebibyte.media/arf/arf/parser"
|
||||||
|
|
||||||
|
// Block represents a scoped block of phrases.
|
||||||
type Block struct {
|
type Block struct {
|
||||||
locatable
|
phrases []Phrase
|
||||||
|
|
||||||
|
// TODO: create a scope struct and embed it
|
||||||
|
}
|
||||||
|
|
||||||
|
func (block Block) ToString (indent int) (output string) {
|
||||||
|
output += doIndent(indent, "block\n")
|
||||||
|
|
||||||
|
// TODO: variables
|
||||||
|
|
||||||
|
for _, phrase := range block.phrases {
|
||||||
|
output += phrase.ToString(indent + 1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// analyzeBlock analyzes a scoped block of phrases.
|
||||||
|
// TODO: have a way to "start out" with a list of variables for things like
|
||||||
|
// arguments, and declarations inside of control flow statements
|
||||||
|
func (analyzer *analysisOperation) analyzeBlock (
|
||||||
|
inputBlock parser.Block,
|
||||||
|
) (
|
||||||
|
block Block,
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
|
for _, inputPhrase := range inputBlock {
|
||||||
|
var outputPhrase Phrase
|
||||||
|
outputPhrase, err = analyzer.analyzePhrase(inputPhrase)
|
||||||
|
block.phrases = append(block.phrases, outputPhrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import "git.tebibyte.media/arf/arf/infoerr"
|
|||||||
// FuncSection represents a type definition section.
|
// FuncSection represents a type definition section.
|
||||||
type FuncSection struct {
|
type FuncSection struct {
|
||||||
sectionBase
|
sectionBase
|
||||||
|
root Block
|
||||||
external bool
|
external bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ func (section FuncSection) ToString (indent int) (output string) {
|
|||||||
output += "\n"
|
output += "\n"
|
||||||
|
|
||||||
// TODO: arguments
|
// TODO: arguments
|
||||||
// TODO: root block
|
output += section.root.ToString(indent + 1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,8 +52,13 @@ func (analyzer *analysisOperation) analyzeFuncSection () (
|
|||||||
|
|
||||||
if inputSection.External() {
|
if inputSection.External() {
|
||||||
outputSection.external = true
|
outputSection.external = true
|
||||||
|
if inputSection.Root() != nil {
|
||||||
|
panic("invalid state: input func is external with non-nil root")
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
outputSection.root, err = analyzer.analyzeBlock(inputSection.Root())
|
||||||
|
if err != nil { return }
|
||||||
// TODO: analyze root block if not nil
|
// TODO: analyze root block if not nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
import "git.tebibyte.media/arf/arf/file"
|
import "git.tebibyte.media/arf/arf/file"
|
||||||
import "git.tebibyte.media/arf/arf/parser"
|
import "git.tebibyte.media/arf/arf/parser"
|
||||||
import "git.tebibyte.media/arf/arf/infoerr"
|
import "git.tebibyte.media/arf/arf/infoerr"
|
||||||
|
|
||||||
|
var validNameRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||||
|
|
||||||
type Phrase interface {
|
type Phrase interface {
|
||||||
// Provided by phraseBase
|
// Provided by phraseBase
|
||||||
Location () (location file.Location)
|
Location () (location file.Location)
|
||||||
@@ -19,6 +22,17 @@ type ArbitraryPhrase struct {
|
|||||||
arguments []Argument
|
arguments []Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (phrase ArbitraryPhrase) ToString (indent int) (output string) {
|
||||||
|
output += doIndent(indent, "phrase\n")
|
||||||
|
output += doIndent(indent + 1, phrase.command, "\n")
|
||||||
|
|
||||||
|
for _, argument := range phrase.arguments {
|
||||||
|
output += argument.ToString(indent + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type CastPhrase struct {
|
type CastPhrase struct {
|
||||||
phraseBase
|
phraseBase
|
||||||
command Argument
|
command Argument
|
||||||
@@ -33,5 +47,41 @@ func (analyzer *analysisOperation) analyzePhrase (
|
|||||||
phrase Phrase,
|
phrase Phrase,
|
||||||
err error,
|
err error,
|
||||||
) {
|
) {
|
||||||
|
base := phraseBase { }
|
||||||
|
base.location = inputPhrase.Location()
|
||||||
|
|
||||||
|
arguments := []Argument { }
|
||||||
|
for index := 0; index < inputPhrase.Length(); index ++ {
|
||||||
|
inputArgument := inputPhrase.Argument(index)
|
||||||
|
|
||||||
|
var argument Argument
|
||||||
|
argument, err = analyzer.analyzeArgument(inputArgument)
|
||||||
|
if err != nil { return }
|
||||||
|
|
||||||
|
arguments = append(arguments, argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch inputPhrase.Kind() {
|
||||||
|
case parser.PhraseKindArbitrary:
|
||||||
|
command := inputPhrase.Command().Value().(string)
|
||||||
|
if !validNameRegex.Match([]byte(command)) {
|
||||||
|
err = inputPhrase.NewError (
|
||||||
|
"command cannot contain characters other " +
|
||||||
|
"than a-z, A-Z, 0-9, underscores, or begin " +
|
||||||
|
"with a number",
|
||||||
|
infoerr.ErrorKindError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
outputPhrase := ArbitraryPhrase {
|
||||||
|
phraseBase: base,
|
||||||
|
command: command,
|
||||||
|
arguments: arguments,
|
||||||
|
}
|
||||||
|
phrase = outputPhrase
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("phrase kind not implemented")
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,17 @@ package parser
|
|||||||
import "git.tebibyte.media/arf/arf/types"
|
import "git.tebibyte.media/arf/arf/types"
|
||||||
|
|
||||||
// LookupSection looks returns the section under the give name. If the section
|
// LookupSection looks returns the section under the give name. If the section
|
||||||
// does not exist, nil is returned.
|
// does not exist, nil is returned. If a method is being searched for, the type
|
||||||
func (tree SyntaxTree) LookupSection (name string) (section Section) {
|
// name of its receiver should be passed. If not, it should just be left blank.
|
||||||
|
func (tree SyntaxTree) LookupSection (
|
||||||
|
receiver string,
|
||||||
|
name string,
|
||||||
|
) (
|
||||||
|
section Section,
|
||||||
|
) {
|
||||||
|
if receiver != "" {
|
||||||
|
name = receiver + "_" + name
|
||||||
|
}
|
||||||
section = tree.sections[name]
|
section = tree.sections[name]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -182,6 +191,12 @@ func (section DataSection) External () (external bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Command returns the phrase's command.
|
||||||
|
func (phrase Phrase) Command () (command Argument) {
|
||||||
|
command = phrase.command
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Kind returns what kind of phrase it is.
|
// Kind returns what kind of phrase it is.
|
||||||
func (phrase Phrase) Kind () (kind PhraseKind) {
|
func (phrase Phrase) Kind () (kind PhraseKind) {
|
||||||
kind = phrase.kind
|
kind = phrase.kind
|
||||||
|
|||||||
@@ -53,7 +53,17 @@ func (parser *parsingOperation) parseBody () (err error) {
|
|||||||
// addSection adds a section to the tree, ensuring it has a unique name within
|
// addSection adds a section to the tree, ensuring it has a unique name within
|
||||||
// the module.
|
// the module.
|
||||||
func (tree *SyntaxTree) addSection (section Section) (err error) {
|
func (tree *SyntaxTree) addSection (section Section) (err error) {
|
||||||
_, exists := tree.sections[section.Name()]
|
index := section.Name()
|
||||||
|
|
||||||
|
funcSection, isFuncSection := section.(FuncSection)
|
||||||
|
if isFuncSection {
|
||||||
|
receiver := funcSection.receiver
|
||||||
|
if receiver != nil {
|
||||||
|
index = receiver.what.points.name.trail[0] + "_" + index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, exists := tree.sections[index]
|
||||||
if exists {
|
if exists {
|
||||||
err = section.NewError (
|
err = section.NewError (
|
||||||
"cannot have multiple sections with the same name",
|
"cannot have multiple sections with the same name",
|
||||||
@@ -61,6 +71,6 @@ func (tree *SyntaxTree) addSection (section Section) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tree.sections[section.Name()] = section
|
tree.sections[index] = section
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ func TestFunc (test *testing.T) {
|
|||||||
checkTree ("../tests/parser/func", false,
|
checkTree ("../tests/parser/func", false,
|
||||||
`:arf
|
`:arf
|
||||||
---
|
---
|
||||||
func ro aBasicExternal
|
func ro bMethod
|
||||||
|
@ bird:{Bird}
|
||||||
> someInput:Int:mut
|
> someInput:Int:mut
|
||||||
< someOutput:Int 4
|
< someOutput:Int 4
|
||||||
---
|
---
|
||||||
external
|
external
|
||||||
func ro bMethod
|
func ro aBasicExternal
|
||||||
@ bird:{Bird}
|
|
||||||
> someInput:Int:mut
|
> someInput:Int:mut
|
||||||
< someOutput:Int 4
|
< someOutput:Int 4
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -306,7 +306,7 @@ func (parser *parsingOperation) parsePhraseCommand () (
|
|||||||
|
|
||||||
// determine semantic role of phrase
|
// determine semantic role of phrase
|
||||||
if command.kind == ArgumentKindString {
|
if command.kind == ArgumentKindString {
|
||||||
kind = PhraseKindCallExternal
|
kind = PhraseKindArbitrary
|
||||||
|
|
||||||
} else if command.kind == ArgumentKindIdentifier {
|
} else if command.kind == ArgumentKindIdentifier {
|
||||||
identifier := command.value.(Identifier)
|
identifier := command.value.(Identifier)
|
||||||
|
|||||||
@@ -231,33 +231,58 @@ type Dereference struct {
|
|||||||
type PhraseKind int
|
type PhraseKind int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PhraseKindCall = iota
|
// [name]
|
||||||
PhraseKindCallExternal
|
PhraseKindCall PhraseKind = iota
|
||||||
|
|
||||||
|
// ["name"]
|
||||||
|
PhraseKindArbitrary
|
||||||
|
|
||||||
|
// [+] [-]
|
||||||
PhraseKindOperator
|
PhraseKindOperator
|
||||||
|
|
||||||
|
// [= x y]
|
||||||
PhraseKindAssign
|
PhraseKindAssign
|
||||||
|
|
||||||
|
// [loc x]
|
||||||
PhraseKindReference
|
PhraseKindReference
|
||||||
|
|
||||||
|
// [cast x T]
|
||||||
PhraseKindCast
|
PhraseKindCast
|
||||||
|
|
||||||
|
// [defer]
|
||||||
PhraseKindDefer
|
PhraseKindDefer
|
||||||
|
|
||||||
|
// [if c]
|
||||||
PhraseKindIf
|
PhraseKindIf
|
||||||
|
|
||||||
|
// [elseif]
|
||||||
PhraseKindElseIf
|
PhraseKindElseIf
|
||||||
|
|
||||||
|
// [else]
|
||||||
PhraseKindElse
|
PhraseKindElse
|
||||||
|
|
||||||
|
// [switch]
|
||||||
PhraseKindSwitch
|
PhraseKindSwitch
|
||||||
|
|
||||||
|
// [case]
|
||||||
PhraseKindCase
|
PhraseKindCase
|
||||||
|
|
||||||
|
// [while c]
|
||||||
PhraseKindWhile
|
PhraseKindWhile
|
||||||
|
|
||||||
|
// [for x y z]
|
||||||
PhraseKindFor
|
PhraseKindFor
|
||||||
)
|
)
|
||||||
|
|
||||||
// Phrase represents a function call or operator. In ARF they are the same
|
// Phrase represents a function call or operator. In ARF they are the same
|
||||||
// syntactical concept.
|
// syntactical concept.
|
||||||
type Phrase struct {
|
type Phrase struct {
|
||||||
location file.Location
|
locatable
|
||||||
returnees []Argument
|
returnees []Argument
|
||||||
multiValuable
|
multiValuable
|
||||||
|
|
||||||
kind PhraseKind
|
kind PhraseKind
|
||||||
|
|
||||||
// TODO: do not have this be an argument. make a string version, and
|
|
||||||
// and identifier version.
|
|
||||||
command Argument
|
command Argument
|
||||||
|
|
||||||
// only applicable for PhraseKindOperator
|
// only applicable for PhraseKindOperator
|
||||||
|
|||||||
Reference in New Issue
Block a user