Browse Source

began work on compiler

added block literals
added folds and functionalizability
master
Pixdigit 2 years ago
parent
commit
69fa3954a7
  1. 8
      ScriptoidParser.g4
  2. 8
      go.mod
  3. 4
      go.sum
  4. 6
      internal/AST/AtomicNode.go
  5. 14
      internal/AST/ErrorNode.go
  6. 29
      internal/AST/Node.go
  7. 86
      internal/AST/ScopeNode.go
  8. 30
      internal/AST/TransformNode.go
  9. 35
      internal/compiler/codeGen.go
  10. 32
      internal/compiler/compiler.go
  11. 26
      internal/printTree.go
  12. 21
      internal/test.go
  13. 58
      internal/treeVisitor.go
  14. 7
      main.go
  15. 8
      test.sct

8
ScriptoidParser.g4

@ -8,10 +8,13 @@ options {
script: scope;
scope: (declarations+=declarationStatement | NEWLINE)*;
block: '{' scope '}';
scope: (lines+=line)* closeIndents+=INDENT*;
line: indents+=INDENT* declaration eos
| NEWLINE
;
declarationStatement: indents+=INDENT* declaration eos;
declaration:
variable
| function
@ -34,6 +37,7 @@ literal:
| STRING_LIT
| function_literal
| call
| block
;

8
go.mod

@ -1,8 +0,0 @@
module gitlab.com/Pixdigit/Scriptoid
go 1.13
require (
github.com/antlr/antlr4 v0.0.0-20200119161855-7a3f40bc341d
gitlab.com/Pixdigit/uniqueID v1.0.0
)

4
go.sum

@ -1,4 +0,0 @@
github.com/antlr/antlr4 v0.0.0-20200119161855-7a3f40bc341d h1:YyyukUZiej+hTJINHjowi57xLQE9SN2KOJ7kYMKhr7I=
github.com/antlr/antlr4 v0.0.0-20200119161855-7a3f40bc341d/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
gitlab.com/Pixdigit/uniqueID v1.0.0 h1:I7Q49mOG6cAbgwtviFUvDwDr01JMm5h/vaatqafLWeQ=
gitlab.com/Pixdigit/uniqueID v1.0.0/go.mod h1:tcfI4jl0vg20J/auXSuCOhCPR9b4gnHJgwxeyHKroTg=

6
internal/AST/AtomicNode.go

@ -11,13 +11,13 @@ const (
)
type AtomicNode struct {
Node
*Node
Type AtomicType
Value interface{}
}
func NewAtomicNode(name string, constantType AtomicType, value interface{}) AtomicNode {
return AtomicNode{
func NewAtomicNode(name string, constantType AtomicType, value interface{}) *AtomicNode {
return &AtomicNode{
NewNode(name),
constantType,
value,

14
internal/AST/ErrorNode.go

@ -1,19 +1,13 @@
package AST
import "gitlab.com/Pixdigit/uniqueID"
type ErrorNode struct {
id uniqueID.ID
*Node
Info string
}
func NewErrorNode(info string) ErrorNode {
return ErrorNode{
id: uniqueID.NewID(),
func NewErrorNode(info string) *ErrorNode {
return &ErrorNode{
Node: NewNode("error"),
Info: info,
}
}
func (en ErrorNode) ID() uniqueID.ID {
return en.id
}

29
internal/AST/Node.go

@ -3,21 +3,42 @@ package AST
import "gitlab.com/Pixdigit/uniqueID"
type Unique interface {
Name() string
SetName(name string)
ID() uniqueID.ID
}
type Functionable interface {
Functionalize()
IsFunctional() bool
}
type Foldable interface {
Unique
Fold()
IsFolded() bool
}
type Node struct {
id uniqueID.ID
Name string
name string
}
func NewNode(name string) Node {
return Node{
func NewNode(name string) *Node {
return &Node{
uniqueID.NewID(),
name,
}
}
func (n Node) ID() uniqueID.ID {
func (n *Node) ID() uniqueID.ID {
return n.id
}
func (n *Node) Name() string {
return n.name
}
func (n *Node) SetName(name string) {
n.name = name
}

86
internal/AST/ScopeNode.go

@ -3,20 +3,20 @@ package AST
import "fmt"
type ScopeNode struct {
Node
Variables []ScopeNode
Constants []AtomicNode
Transforms []TransformNode
Errors []ErrorNode
*Node
Variables []*ScopeNode
Constants []*AtomicNode
Transforms []*TransformNode
Errors []*ErrorNode
}
func NewScopeNode(name string) ScopeNode {
return ScopeNode{
func NewScopeNode(name string) *ScopeNode {
return &ScopeNode{
Node: NewNode(name),
Variables: []ScopeNode{},
Constants: []AtomicNode{},
Transforms: []TransformNode{},
Errors: []ErrorNode{},
Variables: []*ScopeNode{},
Constants: []*AtomicNode{},
Transforms: []*TransformNode{},
Errors: []*ErrorNode{},
}
}
@ -44,19 +44,69 @@ func (sn *ScopeNode) Children() []Unique {
func (sn *ScopeNode) AddChild(node Unique) {
switch t := node.(type) {
case ScopeNode:
case *ScopeNode:
sn.Variables = append(sn.Variables, t)
case AtomicNode:
case *AtomicNode:
sn.Constants = append(sn.Constants, t)
case TransformNode:
case *TransformNode:
sn.Transforms = append(sn.Transforms, t)
case ErrorNode:
case *ErrorNode:
sn.Errors = append(sn.Errors, t)
default:
panic(fmt.Sprintf("%T is not a type a scope can hold", node))
}
}
// func (bn *ScopeNode) AddChildren(nodes []ASTNode) {
// bn.childNodes = append(bn.childNodes, nodes...)
// }
func (sn *ScopeNode) Functionalize() {
for _, fun := range sn.Transforms {
fun.Functionalize()
}
for _, variable := range sn.Variables {
variable.Functionalize()
sn.Transforms = append(sn.Transforms, NewIdentNode(variable.Name(), variable))
}
sn.Variables = []*ScopeNode{}
}
func (sn *ScopeNode) Fold() {
//TODO import parameters into namespace
for _, trans := range sn.Transforms {
trans.Fold()
for _, child := range trans.TransformBlock.Children() {
child.SetName(trans.Name() + "." + child.Name())
if foldable, ok := child.(Foldable); ok {
foldable.Fold()
sn.AddChild(foldable)
} else {
sn.AddChild(child)
}
}
}
sn.Transforms = []*TransformNode{}
}
func (sn ScopeNode) IsFunctional() bool {
isFunctional := len(sn.Variables) == 0
for _, child := range sn.Children() {
switch t := child.(type) {
case Functionable:
isFunctional = isFunctional && t.IsFunctional()
}
}
return isFunctional
}
func (sn ScopeNode) IsFolded() bool {
isFolded := len(sn.Transforms) == 0
for _, child := range sn.Children() {
switch t := child.(type) {
case Foldable:
isFolded = isFolded && t.IsFolded()
}
}
return isFolded
}

30
internal/AST/TransformNode.go

@ -1,15 +1,35 @@
package AST
type TransformNode struct {
Node
Parameters ScopeNode
TransformBlock ScopeNode
*Node
Parameters *ScopeNode
TransformBlock *ScopeNode
}
func NewTransformNode(name string, parameters ScopeNode, transformBlock ScopeNode) TransformNode {
return TransformNode{
func NewTransformNode(name string, parameters *ScopeNode, transformBlock *ScopeNode) *TransformNode {
return &TransformNode{
NewNode(name),
parameters,
transformBlock,
}
}
func NewIdentNode(name string, scope *ScopeNode) *TransformNode {
return NewTransformNode(name, NewScopeNode("params"), scope)
}
func (tn *TransformNode) Functionalize() {
tn.TransformBlock.Functionalize()
}
func (tn *TransformNode) Fold() {
tn.TransformBlock.Fold()
}
func (tn *TransformNode) IsFunctional() bool {
return tn.TransformBlock.IsFunctional()
}
func (tn *TransformNode) IsFolded() bool {
return tn.TransformBlock.IsFolded()
}

35
internal/compiler/codeGen.go

@ -0,0 +1,35 @@
package compiler
import (
"encoding/json"
"errors"
"fmt"
"gitlab.com/Pixdigit/Scriptoid/internal/AST"
"llvm.org/llvm/bindings/go/llvm"
)
func codeGen(entry AST.Unique, comp compiler) (llvm.Value, error) {
fmt.Println("Gen code for " + entry.Name())
var value llvm.Value
switch t := entry.(type) {
case *AST.AtomicNode:
switch t.Type {
case AST.INT:
value = llvm.ConstInt(comp.ctx.Int64Type(), uint64(t.Value.(int)), true)
default:
panic(fmt.Sprintf("Can not generate code for Atomic of type %v", t.Type))
}
case *AST.TransformNode:
if !t.IsFolded() {
return llvm.Value{}, errors.New(fmt.Sprintf("Can not gen code for %v as it is not folded", t.Name()))
}
codeGen(t.TransformBlock, comp)
case *AST.ScopeNode:
s, _ := json.Marshal(t.Children())
panic(fmt.Sprintf("Why is %v still here? Has %+v", t.Name(), string(s)))
default:
panic(fmt.Sprintf("Can not generate code for AST node of type %T", entry))
}
return value, nil
}

32
internal/compiler/compiler.go

@ -0,0 +1,32 @@
package compiler
import (
"errors"
"gitlab.com/Pixdigit/Scriptoid/internal/AST"
"llvm.org/llvm/bindings/go/llvm"
)
type compiler struct {
ctx llvm.Context
module llvm.Module
builder llvm.Builder
}
func newCompiler(moduleName string) compiler {
ctx := llvm.NewContext()
return compiler{
ctx: ctx,
module: ctx.NewModule(moduleName),
builder: llvm.NewBuilder(),
}
}
func Compile(entry *AST.TransformNode) error {
if !entry.IsFunctional() {
return errors.New("Can only compile purely functional ASTs")
}
comp := newCompiler(entry.Name())
_, err := codeGen(entry, comp)
return err
}

26
internal/printTree.go

@ -12,33 +12,29 @@ func printTree(root AST.Unique) {
}
func printIndented(amount int, node AST.Unique) {
fmt.Print(strings.Repeat("\t", amount))
fmt.Print(indent("", amount, "\t"))
switch n := node.(type) {
case AST.ScopeNode:
fmt.Print(n.Name)
children := n.Children()
if (len(children) == 1) {
fmt.Print(" := ")
printIndented(0, children[0])
} else {
case *AST.ScopeNode:
fmt.Println(n.Name() + " {")
for _, child := range n.Children() {
printIndented(amount+1, child)
}}
case AST.AtomicNode:
fmt.Printf("%v (%v)\n", n.Value, n.Type)
case AST.TransformNode:
fmt.Printf("Function %v(", n.Name)
}
fmt.Println(indent("}", amount, "\t"))
case *AST.AtomicNode:
fmt.Printf("%v := %v (%v)\n", n.Name(), n.Value, n.Type)
case *AST.TransformNode:
fmt.Printf("Function %v(", n.Name())
for i, param := range n.Parameters.Variables {
if i > 0 {
fmt.Print(", ")
}
fmt.Printf("%v", param.Name)
fmt.Printf("%v", param.Name())
}
fmt.Println("):")
for _, child := range n.TransformBlock.Children() {
printIndented(amount+1, child)
}
case AST.ErrorNode:
case *AST.ErrorNode:
fmt.Println("Error: ", n.Info)
}
}

21
internal/test.go

@ -27,8 +27,8 @@ func Test() {
if err != nil {
panic("Can not open file: " + fmt.Sprint(err))
}
input_copy, _ := antlr.NewFileStream(os.Args[1])
PrintTokens(input_copy)
//input_copy, _ := antlr.NewFileStream(os.Args[1])
//PrintTokens(input_copy)
lexer := parser.NewScriptoidLexer(input)
stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
@ -40,7 +40,22 @@ func Test() {
visitor := NewScriptoidTreeVisitor(true)
astTree := visitor.VisitScript(p.Script().(*parser.ScriptContext))
_ = astTree
printTree(astTree)
fmt.Println()
astTree.Functionalize()
printTree(astTree)
fmt.Println()
astTree.Fold()
printTree(astTree)
fmt.Println()
//_, _ := json.MarshalIndent(astTree, "", "\t")
//fmt.Printf("%+v\n", astTree)
// err = compiler.Compile(astTree)
// if err != nil {
// panic(err)
// }
}

58
internal/treeVisitor.go

@ -33,40 +33,40 @@ func (s ScriptoidTreeVisitor) printf(format string, arguments ...interface{}) {
}
}
func (s ScriptoidTreeVisitor) VisitScript(ctx *parser.ScriptContext) AST.ScopeNode {
func (s ScriptoidTreeVisitor) VisitScript(ctx *parser.ScriptContext) *AST.TransformNode {
s.printf("Visiting Script: %v", indent(ctx.GetText(), 1, "\t"))
scope := s.VisitScope(ctx.Scope().(*parser.ScopeContext))
//TODO: replace Script name by module or file name
scope.Name = "Script"
return scope
trans := AST.NewIdentNode("Script", scope)
return trans
}
func (s ScriptoidTreeVisitor) VisitScope(ctx *parser.ScopeContext) AST.ScopeNode {
declarationStatements := ctx.GetDeclarations()
func (s ScriptoidTreeVisitor) VisitScope(ctx *parser.ScopeContext) *AST.ScopeNode {
lines := ctx.GetLines()
s.printf("Visiting Scope: %v", indent(ctx.GetText(), 1, "\t"))
s.printf("Scope has %v declaration statements", len(declarationStatements))
s.printf("Scope has %v lines", len(lines))
s.enter()
defer s.exit()
scope := AST.NewScopeNode("anonymous")
for _, child := range declarationStatements {
declarationStatement := s.VisitDeclarationStatement(child.(*parser.DeclarationStatementContext))
scope.AddChild(declarationStatement)
for _, line := range lines {
lineCtx := line.(*parser.LineContext)
//TODO: validate indents
declaration := lineCtx.Declaration()
if declaration!= nil {
node := s.VisitDeclaration(declaration.(*parser.DeclarationContext))
scope.AddChild(node)
}
}
return scope
}
func (s ScriptoidTreeVisitor) VisitDeclarationStatement(ctx *parser.DeclarationStatementContext) AST.Unique {
s.printf("Visiting Declaration Statement with %v indents: %v", len(ctx.GetIndents()), ctx.GetText())
s.enter()
defer s.exit()
//TODO: validate indents
return s.VisitDeclaration(ctx.Declaration().(*parser.DeclarationContext))
}
func (s ScriptoidTreeVisitor) VisitDeclaration(ctx *parser.DeclarationContext) AST.Unique {
s.printf("Visiting Declaration: %v", ctx.GetText())
s.enter()
@ -94,12 +94,10 @@ func (s ScriptoidTreeVisitor) VisitVariable(ctx *parser.VariableContext) AST.Uni
defer s.exit()
var_name := ctx.IDENTIFIER().GetText()
variable := AST.NewScopeNode(var_name)
literal := s.VisitLiteral(ctx.Literal().(*parser.LiteralContext))
literal.SetName(var_name)
variable.AddChild(literal)
return variable
return literal
}
func (s ScriptoidTreeVisitor) VisitLiteral(ctx *parser.LiteralContext) AST.Unique {
@ -115,6 +113,7 @@ func (s ScriptoidTreeVisitor) VisitLiteral(ctx *parser.LiteralContext) AST.Uniqu
str := ctx.STRING_LIT()
fun := ctx.Function_literal()
call := ctx.Call()
block := ctx.Block()
if integer != nil {
node.Type = AST.INT
@ -133,20 +132,15 @@ func (s ScriptoidTreeVisitor) VisitLiteral(ctx *parser.LiteralContext) AST.Uniqu
return AST.NewTransformNode("literal", parameters, scope)
} else if call != nil {
return AST.NewErrorNode("calls are not implemented yet")
} else if block != nil {
return s.VisitBlock(block.(*parser.BlockContext))
} else {
panic(fmt.Sprintf("Literal is not of a known type. Rule: %+v", ctx.GetParser().(*parser.ScriptoidParser).RuleNames[ctx.GetRuleContext().GetRuleIndex()]))
panic(fmt.Sprintf("Literal is not of a known type. Token: %v", ctx.GetText()))
}
_ = integer
_ = float
_ = str
_ = fun
_ = call
return node
}
func (s ScriptoidTreeVisitor) VisitFunction(ctx *parser.FunctionContext) AST.TransformNode {
func (s ScriptoidTreeVisitor) VisitFunction(ctx *parser.FunctionContext) *AST.TransformNode {
s.printf("Visiting Function \"%v\"", ctx.IDENTIFIER().GetSymbol().GetText())
s.enter()
defer s.exit()
@ -158,11 +152,11 @@ func (s ScriptoidTreeVisitor) VisitFunction(ctx *parser.FunctionContext) AST.Tra
return AST.NewTransformNode(func_name, parameters, scope)
}
func (s *ScriptoidTreeVisitor) VisitBlock(ctx *parser.BlockContext) AST.ScopeNode {
func (s *ScriptoidTreeVisitor) VisitBlock(ctx *parser.BlockContext) *AST.ScopeNode {
return s.VisitScope(ctx.Scope().(*parser.ScopeContext))
}
func (s *ScriptoidTreeVisitor) VisitParameters(ctx *parser.ParametersContext) AST.ScopeNode {
func (s *ScriptoidTreeVisitor) VisitParameters(ctx *parser.ParametersContext) *AST.ScopeNode {
s.enter()
defer s.exit()
s.printf("Found %v Parameters", len(ctx.AllIDENTIFIER()))

7
main.go

@ -0,0 +1,7 @@
package main
//This file exists for go to accept the module
func main() {
}

8
test.sct

@ -13,6 +13,14 @@ func add: a, b {
var res = add(test, 6)
var lit = {
var a = {
var a_one = 1
var a_two = 2
}
var b = 2
}
var test2 = (a, b) => {
var x = 2
}

Loading…
Cancel
Save