diff options
| author | Kyle Gunger <kgunger12@gmail.com> | 2021-11-19 01:39:05 -0500 | 
|---|---|---|
| committer | Kyle Gunger <kgunger12@gmail.com> | 2021-11-19 01:39:05 -0500 | 
| commit | 96cf52263053db6bc3069c9fbc664ed0725ac41e (patch) | |
| tree | f3dca802ad7413a9aa614e73fc593a0e28e6fdfb /src/texec | |
| parent | 8cdf25536841a698ad6229f73cdf8ef5ccc1e5fa (diff) | |
Some refactoring, clearing out eval
+ Fixed BuildRoot
+ Refactored world.go
- Deleted most of eval, I'm going to re-do it.
Diffstat (limited to 'src/texec')
| -rw-r--r-- | src/texec/eval.go | 174 | ||||
| -rw-r--r-- | src/texec/libtnsl.go | 72 | ||||
| -rw-r--r-- | src/texec/world.go | 36 | ||||
| -rw-r--r-- | src/texec/worldbuilder.go | 66 | 
4 files changed, 147 insertions, 201 deletions
| 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" +// Don't want to deal with this rn -// 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 -} +/* +	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 -// 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 -					} -				} -			} -		} -	} +	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)) +	for i := 0; i < len(a.T.Path); i++ { +		if a.T.Path[i] != b.T.Path[i] { +			return false  		} - -		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) -		} - -		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  } |