summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/exec.go2
-rw-r--r--src/parse.go8
-rw-r--r--src/texec/eval.go176
-rw-r--r--src/texec/libtnsl.go72
-rw-r--r--src/texec/world.go36
-rw-r--r--src/texec/worldbuilder.go66
6 files changed, 156 insertions, 204 deletions
diff --git a/src/exec.go b/src/exec.go
index b9a74f8..6213e92 100644
--- a/src/exec.go
+++ b/src/exec.go
@@ -28,5 +28,5 @@ func main() {
root := texec.BuildRoot(*inputFile)
- texec.EvalTNSL(&root, *progFlags)
+ //texec.EvalTNSL(&root, *progFlags)
} \ No newline at end of file
diff --git a/src/parse.go b/src/parse.go
index 7849857..79bf013 100644
--- a/src/parse.go
+++ b/src/parse.go
@@ -18,6 +18,7 @@ package main
import "fmt"
import "tparse"
+import "texec"
import "flag"
import "os"
@@ -35,14 +36,19 @@ func main() {
return
}
- tokens := tparse.TokenizeFile(*inputFile)
+
switch *writeLevel {
case 0:
+ tokens := tparse.TokenizeFile(*inputFile)
fd.WriteString(fmt.Sprint(tokens) + "\n")
case 1:
+ tokens := tparse.TokenizeFile(*inputFile)
tree := tparse.MakeTree(&tokens, *inputFile)
fd.WriteString(fmt.Sprint(tree) + "\n")
+ case 2:
+ root := texec.BuildRoot(*inputFile)
+ fd.WriteString(fmt.Sprint(root) + "\n")
}
fd.Close()
diff --git a/src/texec/eval.go b/src/texec/eval.go
index 9900194..4aefd5a 100644
--- a/src/texec/eval.go
+++ b/src/texec/eval.go
@@ -16,158 +16,58 @@
package texec
-import "strings"
-import "strconv"
-import "unicode"
-import "tparse"
-import "fmt"
-
-// Check if a block is the main function
-func funcName(n tparse.Node) string {
- if n.Data.Data == "block" {
- if n.Sub[0].Data.Data == "bdef" {
- for i := 0; i < len(n.Sub[0].Sub); i++ {
- if n.Sub[0].Sub[i].Data.Type == tparse.DEFWORD {
- return n.Sub[0].Sub[i].Data.Data
- }
- }
- }
- }
- return ""
-}
-
-// Default values for variables
-func defaultVaule(t string) interface{} {
- switch t {
- case "int", "uint", "int8", "uint8", "char", "charp":
- return 0
- case "string":
- return ""
- }
- return nil
-}
-
-// Match specific type (t) with general type (g)
-func typeMatches(t, g string) bool {
- switch t {
- case "int", "uint", "int8", "uint8":
- return g == "integer"
- case "float":
- return g == "float"
- case "char", "charp":
- return g == "char"
- case "string":
- return g == "string"
- }
- return false
-}
+// Don't want to deal with this rn
-// Get the control flow's name
-func cfType(n tparse.Node) string {
- if n.Data.Data == "block" {
- if n.Sub[0].Data.Data == "bdef" {
- for i := 0; i < len(n.Sub[0].Sub); i++ {
- if n.Sub[0].Sub[i].Data.Type == tparse.KEYWORD {
- if n.Sub[0].Sub[i].Data.Data == "if" || n.Sub[0].Sub[i].Data.Data == "elif" || n.Sub[0].Sub[i].Data.Data == "else" || n.Sub[0].Sub[i].Data.Data == "match" || n.Sub[0].Sub[i].Data.Data == "case" || n.Sub[0].Sub[i].Data.Data == "loop" {
- return n.Sub[0].Sub[i].Data.Data
- }
- }
- }
- }
- }
+/*
+ So here's what I care to support at present:
+ Type checking, basic types, writing to stdout or a file
+ Variable and state contexts
+ Reading from files
+ Raw structs
+ Appending to arrays
+ Calling functions and methods
+ libtnsl stub
+
+ This subset should theoretically be enough to write a compiler.
+*/
- return ""
-}
+//################
+//# Helper Funcs #
+//################
-// Get type as string from nodes
-func evalType(n tparse.Node) string {
- return ""
-}
-
-// Returns generated value and general "type" of value (string, number)
-func evalPreLiteral(n tparse.Node) string {
- r := tparse.StringAsRunes(n.Data.Data)
- l := len(r)
- if r[0] == '"' || r[0] == '\'' {
- return tparse.RunesAsString(r[1:l - 1])
+func equateType(a, b TType) bool {
+ if len(a.Pre) != len(b.Pre) || len(a.Post) != len(b.Post) {
+ return false
+ } else if len(a.T.Path) != len(b.T.Path) {
+ return false
}
- return ""
-}
-// Returns generated value and general "type" of value (string, number)
-func evalLiteral(n tparse.Node) (interface{}, string) {
- r := tparse.StringAsRunes(n.Data.Data)
- l := len(r)
-
- if r[0] == '"' {
- return tparse.RunesAsString(r[1:l - 1]), "string"
- } else if r[0] == '\'' {
- return tparse.RunesAsString(r[1:l - 1]), "char"
- } else if unicode.IsNumber(r[0]) {
- if strings.Contains(n.Data.Data, ".") {
- f, _ := strconv.ParseFloat(n.Data.Data, 64)
- return f, "float"
- } else {
- i, _ := strconv.Atoi(n.Data.Data)
- return i, "integer"
+ for i := 0; i < len(a.Pre); i++ {
+ if a.Pre[i] != b.Pre[i] {
+ return false
}
}
- return nil, ""
-}
-
-// Evaluates a definition and sets up a TVariable in the context's var map
-func evalDef(n tparse.Node, ctx *TContext) {
- vars := len(ctx.VarMap) - 1
-
- t := evalType(n.Sub[0])
-
- for i := 0; i < len(n.Sub[1].Sub); i++ {
- name := n.Sub[1].Sub[i].Data.Data
-
- _, prs := ctx.VarMap[vars][name]
- if prs {
- panic(fmt.Sprintf("Attempted re-definition of a variable %v", name))
- }
-
- val := defaultVaule(t)
- if n.Sub[1].Sub[i].Data.Data == "=" {
- name = n.Sub[1].Sub[i].Sub[0].Data.Data
- val = evalValue(n.Sub[1].Sub[i].Sub[1], ctx)
+ for i := 0; i < len(a.T.Path); i++ {
+ if a.T.Path[i] != b.T.Path[i] {
+ return false
}
-
- ctx.VarMap[vars][name] = TVariable{t, val}
}
-}
-func delScopeVars(sV []string, ctx *TContext) {
- m := len(ctx.VarMap) - 1
- for i := 0; i < len(sV); i++ {
- delete(ctx.VarMap[m], sV[i])
+ if a.T.Name != b.T.Name {
+ return false
}
-}
-// Evaluates a value statement
-func evalValue(artifact tparse.Node, ctx *TContext) interface{} {
- vars := len(ctx.VarMap) - 1
-}
-
-// Evaluates a loop
-func evalLoop(artifact tparse.Node, ctx *TContext) {
-
-}
-
-func evalIf(artifact tparse.Node, ctx *TContext) bool {
- var scopeVars []string
-}
+ for i := 0; i < len(a.Post); i++ {
+ if a.Post[i] != b.Post[i] {
+ return false
+ }
+ }
-// Evaluate a block (Assume that all blocks have only one output for now)
-func evalBlock(artifact tparse.Node, ctx *TContext) interface{} {
-
+ return true;
}
+//#################
+//# Runtime funcs #
+//#################
-// EvalTNSL starts the evaluation on the root TModule's main function with the given flags passed to the program
-func EvalTNSL(root *TModule, f string) {
- flags := strings.Split(f, " ")
-} \ No newline at end of file
diff --git a/src/texec/libtnsl.go b/src/texec/libtnsl.go
index 1d36892..8dedfbf 100644
--- a/src/texec/libtnsl.go
+++ b/src/texec/libtnsl.go
@@ -30,54 +30,69 @@ import (
- io.File API for file objects
*/
+// I really hope this works.
+
+// Generic in-built types
+var (
+
+ tFile = TType{Pre: []string{}, T: TArtifact{Path: []string{"tnsl", "io"}, Name: "File"}, Post: []string{}}
+ tString = TType{Pre: []string{"{}"}, T: TArtifact{Path: []string{}, Name:"charp"}, Post: []string{}}
+ tInt = TType{Pre: []string{}, T: TArtifact{Path: []string{}, Name:"int"}, Post: []string{}}
+ tFloat = TType{Pre: []string{}, T: TArtifact{Path: []string{}, Name:"float"}, Post: []string{}}
+ tCharp = TType{Pre: []string{}, T: TArtifact{Path: []string{}, Name:"charp"}, Post: []string{}}
+ tNull = TType{Pre: []string{}, T: TArtifact{Path: []string{}, Name: "null"}, Post: []string{}}
+)
+
// tells if the stub supports a function
-func tnslResolve(callPath TPath) bool {
- l := len(callPath.Module)
- if l < 2 || l > 3 || callPath.Module[0] != "tnsl" || callPath.Module[1] != "io" {
- return false
+func tnslResolve(callPath TArtifact) int {
+ l := len(callPath.Path)
+ if l < 2 || l > 3 || callPath.Path[0] != "tnsl" || callPath.Path[1] != "io" {
+ return -1
}
- if l > 2 && callPath.Module[2] != "File" {
- return false
+ if l > 2 && callPath.Path[2] != "File" {
+ return -1
}
if l > 2 {
- if callPath.Artifact == "write" || callPath.Artifact == "read" || callPath.Artifact == "close" {
- return true;
+ if callPath.Name == "write" || callPath.Name == "read" || callPath.Name == "close" {
+ return 1;
}
} else {
- if callPath.Artifact == "print" || callPath.Artifact == "println" || callPath.Artifact == "open_file" {
- return true;
+ if callPath.Name == "print" || callPath.Name == "println" || callPath.Name == "open_file" {
+ return 0;
}
}
- return false
+ return -1
}
// evaluate a function call.
// in is the variable in (if any)
// out is the variable out (if any)
// function is the name of the function
-func tnslEval(in, out *TVariable, function string) {
+func tnslEval(in TVariable, function string) TVariable {
switch function {
case "print":
- tprint(*in)
+ tprint(in)
case "println":
- tprintln(*in)
+ tprintln(in)
case "open_file":
- topen_file(*in, out)
+ return topen_file(in)
}
+ return TVariable{tNull, nil}
}
// evaluate a call on a file object
-func tnslFileEval(file, in, out *TVariable, function string) {
+func tnslFileEval(file, in TVariable, function string) TVariable {
switch function {
case "close":
tfile_close(file)
case "read":
- tfile_read(file, out)
+ return tfile_read(file)
case "write":
tfile_write(file, in)
}
+ return TVariable{tNull, nil}
}
// Generic IO funcs
@@ -90,45 +105,42 @@ func tprintln(in TVariable) {
fmt.Printf("%v\n", in.Data)
}
-func topen_file(in TVariable, out *TVariable) {
- if in.Type != "string" {
+func topen_file(in TVariable) TVariable {
+ if equateType(in.Type, tString) {
panic("Tried to open a file, but did not use a string type for the file name.")
}
fd, err := os.Create(in.Data.(string))
if err != nil {
panic(fmt.Sprintf("Failed to open file %v as requested by the program. Aborting.\n%v", in.Data, err))
}
- out.Type = "tnsl.io.File"
- out.Data = fd
+ return TVariable{tFile, fd}
}
// File API
// tnsl.io.File.close
-func tfile_close(file *TVariable) {
- if file.Type == "tnsl.io.File" {
+func tfile_close(file TVariable) {
+ if equateType(file.Type, tFile) {
(file.Data).(*os.File).Close()
}
}
// tnsl.io.File.read
-func tfile_read(file, out *TVariable) {
+func tfile_read(file TVariable) TVariable {
b := []byte{1}
(file.Data).(*os.File).Read(b)
- if out.Data == "uint8" || out.Data == "int8" {
- out.Data = b[0]
- }
+ return TVariable{tCharp, rune(b[0])}
}
// tnsl.io.File.write
-func tfile_write(file, in *TVariable) {
+func tfile_write(file, in TVariable) {
b := []byte{0}
- if in.Data == "uint8" || in.Data == "int8" {
+ if equateType(file.Type, tFile) && (equateType(in.Type, tCharp) || equateType(in.Type, tInt)) {
b[0] = (in.Data).(byte)
+ (file.Data).(*os.File).Write(b)
} else {
(file.Data).(*os.File).Close()
panic(fmt.Sprintf("Failed to write to file, attempted to use unsupported type (%v)\n", in.Type))
}
- (file.Data).(*os.File).Write(b)
}
diff --git a/src/texec/world.go b/src/texec/world.go
index 86660bc..83c50fd 100644
--- a/src/texec/world.go
+++ b/src/texec/world.go
@@ -18,31 +18,37 @@ package texec
import "tparse"
+// TArtifact represents the path to a specific named object in the node tree.
+type TArtifact struct {
+ Path []string
+ Name string
+}
+
+// TType represents the type of a variable (including pre and post unary ops)
+type TType struct {
+ Pre []string
+ T TArtifact
+ Post []string
+}
+
// TVariable represents a single variable in the program
type TVariable struct {
- Type string
+ Type TType
Data interface{}
}
-// TPath represents a pointer to the current module and file
-// that the thread is working in.
-type TPath struct {
- Module []string
- Artifact string
-}
+type VarMap map[string]TVariable
-// TContext represents a single thread.
+// TContext represents a single call context.
type TContext struct {
- CallStack []tparse.Node
- CallEnv []TPath
- VarMap []map[string]TVariable
+ CallEnv TArtifact
+ Vars VarMap
}
// TModule represents a collection of files and sub-modules in a program
type TModule struct {
- Name string
- Files []tparse.Node
- Globals []map[string]TVariable
- Sub []TModule
+ Name string
+ Artifacts []tparse.Node
+ Sub []TModule
}
diff --git a/src/texec/worldbuilder.go b/src/texec/worldbuilder.go
index f3cd6e6..d85f1ac 100644
--- a/src/texec/worldbuilder.go
+++ b/src/texec/worldbuilder.go
@@ -18,28 +18,65 @@ package texec
import (
"tparse"
- "path"
)
/**
worldbuilder.go - take in a file name and construct a root TModule based on it.
*/
+// Note: This is good enough, I guess. Gonna mark this as the final version, only update on major errors.
+
+// Supported features:
+// Importing other files
+// Sub-modules across files
+
+// Semi-borked sub-folders:
+// Because the builder doesn't preserve the paths you are taking, it will not figure out which folder each file is in properly.
+// Technically, you could work around this by making all imports in EVERY FILE EVERYWHERE look as if they are pathed from the folder
+// where the root file is, but this would be a headache. I am just planning on fixing this in the full compiler.
+
+// Returns generated value and general "type" of value (string, number)
+func evalPreLiteral(n tparse.Node) string {
+ r := tparse.StringAsRunes(n.Data.Data)
+ l := len(r)
+ if r[0] == '"' || r[0] == '\'' {
+ return tparse.RunesAsString(r[1:l - 1])
+ }
+ return ""
+}
+
+// Parse a file and make an AST from it.
func parseFile(p string) tparse.Node {
tokens := tparse.TokenizeFile(p)
return tparse.MakeTree(&(tokens), p)
}
+// Import a file and auto-import sub-modules and files
+func importFile(f string, m *TModule) {
+ froot := parseFile(f)
+ for n := 0 ; n < len(froot.Sub) ; n++ {
+ if froot.Sub[n].Data.Data == "block" {
+ if froot.Sub[n].Sub[0].Sub[0].Data.Data == "module" {
+ m.Sub = append(m.Sub, buildModule(froot.Sub[n]))
+ } else {
+ m.Artifacts = append(m.Artifacts, froot.Sub[n])
+ }
+ } else if froot.Sub[n].Data.Data == "include" {
+ importFile(evalPreLiteral(froot.Sub[n].Sub[0]), m)
+ } else {
+ m.Artifacts = append(m.Artifacts, froot.Sub[n])
+ }
+ }
+}
+
+// Build a module from a module block node
func buildModule(module tparse.Node) TModule {
out := TModule{}
+ out.Name = module.Sub[0].Sub[0].Sub[0].Data.Data
- for n := 0 ; n < len(module.Sub) ; n++ {
-
- switch module.Sub[n].Data.Type {
- case 11:
-
- case 10:
-
+ for n := 1 ; n < len(module.Sub) ; n++ {
+ if module.Sub[n].Data.Data == "include" {
+ importFile(evalPreLiteral(module.Sub[n].Sub[0]), &out)
}
}
@@ -47,19 +84,10 @@ func buildModule(module tparse.Node) TModule {
}
// BuildRoot builds the root module, ready for eval
-func BuildRoot(file tparse.Node) TModule {
+func BuildRoot(file string) TModule {
out := TModule{}
- out.Files = append(out.Files, file)
-
- for n := 0 ; n < len(file.Sub) ; n++ {
-
- switch file.Sub[n].Data.Type {
- case 11:
-
- case 10:
- }
- }
+ importFile(file, &out)
return out
}