Created
September 28, 2020 08:31
-
-
Save ducc/39c631c64e0150b73230e642ac58dc12 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"regexp" | |
"sort" | |
"strconv" | |
"strings" | |
) | |
func main() { | |
input := ` | |
returnFirst 2 = | |
| i64(0) | |
| take | |
addOne 2 = | |
| returnFirst | |
| i64(1) | |
| add | |
| is10 | |
is10 1 = | |
| i64(10) | |
| equal ? returnFirst : addOne | |
countTo10 0 = | |
| i64(1) | |
| is10 | |
main 0 = | |
| countTo10 | |
` | |
run(input) | |
} | |
/* | |
package main | |
import ( | |
"fmt" | |
) | |
func returnFirst(var1 []interface{}) interface{} { | |
var var2 interface{} = var1[0] | |
var var3 int64 = var2.(int64) | |
return var3 | |
} | |
func addOne(var1 []interface{}) interface{} { | |
var var2 interface{} = var1[0] | |
var var3 interface{} = var1[1] | |
var var4 interface{} = returnFirst([]interface{}{var2, var3}) | |
var var5 int64 = var4.(int64) | |
var var6 int64 = 1 | |
var var7 int64 = var5 + var6 | |
return is10([]interface{}{var7}) | |
} | |
func is10(var1 []interface{}) interface{} { | |
var var2 int64 = var1[0].(int64) | |
var var3 int64 = 10 | |
if var2 == var3 { | |
var var4 interface{} = returnFirst([]interface{}{var2, var3}) | |
return var4 | |
} else { | |
var var5 interface{} = addOne([]interface{}{var2, var3}) | |
return var5 | |
} | |
} | |
func countTo10(var1 []interface{}) interface{} { | |
var var2 int64 = 1 | |
var var3 interface{} = is10([]interface{}{var2}) | |
fmt.Println(var3) | |
return struct{}{} | |
} | |
func main() { | |
_ = countTo10([]interface{}{}) | |
} | |
*/ | |
func parseRawBlocks(input string) []string { | |
var blockRegex = regexp.MustCompile(`(?m)([a-zA-Z0-9]+\s\d{1,100}\s=\n)(?:(?:\|\s.+)\n)+`) | |
blockMatches := blockRegex.FindAllString(input, -1) | |
for i, blockMatch := range blockMatches { | |
fmt.Printf("=== block match %d:\n%s\n", i, blockMatch) | |
} | |
return blockMatches | |
} | |
func parseBlocks(rawBlocks []string) []Block { | |
blocks := make([]Block, 0) | |
for _, blockMatch := range rawBlocks { | |
var functionName string | |
var functionArgCount int64 | |
blockInstructions := make([]interface{}, 0) | |
for i, line := range strings.Split(cleanInput(blockMatch), "\n") { | |
if i == 0 { | |
functionDecl := line[:strings.Index(line, "=")-1] | |
splits := strings.Split(strings.TrimSpace(functionDecl), " ") | |
functionName = splits[0] | |
functionArgCount, _ = strconv.ParseInt(splits[1], 10, 64) | |
continue | |
} else if strings.HasPrefix(line, "|") { | |
line = line[2:] | |
} | |
var value interface{} | |
if strings.HasPrefix(line, "i64(") { | |
content := line[4:strings.LastIndex(line, ")")] | |
intVal, _ := strconv.ParseInt(content, 10, 64) | |
value = intValue(intVal) | |
} else if strings.Contains(line, "?") { | |
calledFunc := line[:strings.Index(line, "?")-1] | |
trueFunc := line[strings.Index(line, "?")+2:strings.Index(line, ":")-1] | |
if strings.Contains(line, ":") { | |
falseFunc := line[strings.Index(line, ":")+2:] | |
value = functionCallWithConditionalValue(calledFunc, trueFunc, falseFunc) | |
} else { | |
value = functionCallWithConditionalValue(calledFunc, trueFunc, "") | |
} | |
} else { | |
value = functionCallValue(line) | |
} | |
blockInstructions = append(blockInstructions, value) | |
} | |
for _, blockInstruction := range blockInstructions { | |
fmt.Println(blockInstruction) | |
} | |
blocks = append(blocks, newBlock(functionName, functionArgCount, blockInstructions)) | |
} | |
return blocks | |
} | |
func registerBuiltinFunctions(output map[string]Function, programOutput *[]string) { | |
output["add"] = func(v []interface{}) interface{} { | |
fmt.Println("add", v) | |
return Int64Value{Value: v[0].(Int64Value).Value + v[1].(Int64Value).Value} | |
} | |
output["sub"] = func(v []interface{}) interface{} { | |
fmt.Println("sub", v) | |
return Int64Value{Value: v[0].(Int64Value).Value - v[1].(Int64Value).Value} | |
} | |
output["equal"] = func(v []interface{}) interface{} { | |
fmt.Println("equal", v) | |
return BoolValue{Value: v[0] == v[1]} | |
} | |
output["more"] = func(v []interface{}) interface{} { | |
fmt.Println("more", v) | |
return BoolValue{Value: v[0].(Int64Value).Value > v[1].(Int64Value).Value} | |
} | |
output["take"] = func(v []interface{}) interface{} { | |
fmt.Println("take", v) | |
index := v[len(v)-1].(Int64Value).Value | |
return v[index] | |
} | |
output["drop"] = func(v []interface{}) interface{} { | |
fmt.Println("drop") | |
return None{} | |
} | |
output["print"] = func(v []interface{}) interface{} { | |
values := make([]string, 0) | |
for _, v := range v { | |
switch v := v.(type) { | |
case Int64Value: | |
values = append(values, fmt.Sprint(v.Value)) | |
case BoolValue: | |
var text string | |
if v.Value { | |
text = "yes" | |
} else { | |
text = "no" | |
} | |
values = append(values, text) | |
default: | |
panic(fmt.Sprintf("unknown type: %s", v)) | |
} | |
} | |
*programOutput = append(*programOutput, strings.Join(values, " ")) | |
return nil | |
} | |
} | |
func run(input string) { | |
/*programOutput := make([]string, 0) | |
functions := make(map[string]Function) | |
registerBuiltinFunctions(functions, &programOutput) | |
rawBlocks := parseRawBlocks(input) | |
blocks := parseBlocks(rawBlocks) | |
fmt.Println("============ running =============") | |
for _, block := range blocks { | |
block := block | |
functions[block.FunctionName] = func(input []interface{}) interface{} { | |
return runInstructions(functions, block.Instructions, input) | |
} | |
} | |
_ = functions["main"]([]interface{}{}) | |
fmt.Printf("========= output =========\n%s\n", strings.Join(programOutput, "\n"))*/ | |
buf := bytes.NewBuffer([]byte{}) | |
write := func(s string, args ...interface{}) { | |
buf.WriteString(fmt.Sprintf(s, args...)) | |
} | |
write("package main\n") | |
write("import \"fmt\"\n") | |
write("func add(input []interface{}) interface{} {\nreturn input[0].(int64) + input[1].(int64)\n}\n") | |
write("func sub(input []interface{}) interface{} {\nreturn input[0].(int64) - input[1].(int64)\n}\n") | |
write("func equal(input []interface{}) interface{} {\nreturn input[0] == input[1]\n}\n") | |
write("func more(input []interface{}) interface{} {\nreturn input[0].(int64) > input[1].(int64)\n}\n") | |
write("func take(input []interface{}) interface{} {\nindex := input[len(input)-1].(int64)\nreturn input[index]\n}\n") | |
write("func print(input []interface{}) interface{} {\nfmt.Println(input)\nreturn struct{}{}\n}\n") | |
blocks := parseBlocks(parseRawBlocks(input)) | |
getFunctionArgCount := func(name string) int { | |
switch name { | |
case "add": | |
return 2 | |
case "sub": | |
return 2 | |
case "equal": | |
return 2 | |
case "more": | |
return 2 | |
case "take": | |
return 3 | |
case "drop": | |
return 0 | |
case "print": | |
return 1 | |
} | |
for _, block := range blocks { | |
if block.FunctionName == name { | |
return int(block.FunctionArgsCount) | |
} | |
} | |
return 0 | |
} | |
for _, block := range blocks { | |
if block.FunctionName == "main" { | |
write("func main() {\n") | |
} else { | |
write("func %s(var1 []interface{}) interface{} {\n", block.FunctionName) | |
} | |
i := 1 | |
for idx, instruction := range block.Instructions { | |
i++ | |
switch v := instruction.(type) { | |
case Int64Value: | |
write("var var%d interface{} = %d\n", i, v.Value) | |
if idx == len(block.Instructions) - 1 { | |
write("return var%d\n", i) | |
} | |
case FunctionCallValue: | |
args := make([]string, 0) | |
argCount := getFunctionArgCount(v.Function) | |
for x := 0; x < argCount; x++ { | |
args = append(args, fmt.Sprintf("var%d", i-(x+1))) | |
} | |
sort.Strings(args) | |
write("var var%d interface{} = %s([]interface{}{%s})\n", i, v.Function, strings.Join(args, ", ")) | |
if idx == len(block.Instructions) - 1 { | |
if block.FunctionName == "main" { | |
write("_ = var%d\n", i) | |
} else { | |
write("return var%d\n", i) | |
} | |
} | |
case FunctionCallWithConditionalValue: | |
args := make([]string, 0) | |
for x := 0; x < getFunctionArgCount(v.Func.Function); x++ { | |
args = append(args, fmt.Sprintf("var%d", i-(x+1))) | |
} | |
sort.Strings(args) | |
write("var var%d bool = %s([]interface{}{%s}).(bool)\n", i, v.Func.Function, strings.Join(args, ", ")) | |
write("if var%d {\n", i) | |
i++ | |
write("var var%d interface{} = %s([]interface{}{%s})\n", i, v.True.Function, strings.Join(args, ", ")) | |
write("return var%d\n", i) | |
write("} else {\n") | |
i++ | |
write("var var%d interface{} = %s([]interface{}{%s})\n", i, v.False.Function, strings.Join(args, ", ")) | |
write("return var%d\n", i) | |
write("}\n") | |
} | |
} | |
write("}\n\n") | |
//break // todo remove | |
} | |
fmt.Println(buf.String()) | |
} | |
func runInstructions(functions map[string]Function, instructions []interface{}, input []interface{}) interface{} { | |
values := input | |
for _, instruction := range instructions { | |
switch instruction := instruction.(type) { | |
case Int64Value: | |
values = append(values, instruction) | |
case FunctionCallValue: | |
result := functions[instruction.Function](values) | |
values = make([]interface{}, 0) | |
values = append(values, result) | |
case FunctionCallWithConditionalValue: | |
result := functions[instruction.Func.Function](values).(BoolValue).Value | |
if result { | |
result := functions[instruction.True.Function](values) | |
values = make([]interface{}, 0) | |
values = append(values, result) | |
} else { | |
result := functions[instruction.False.Function](values) | |
values = make([]interface{}, 0) | |
values = append(values, result) | |
} | |
} | |
} | |
if len(values) == 0 { | |
return None{} | |
} else { | |
return values[0] | |
} | |
} | |
func cleanInput(input string) string { | |
lines := strings.Split(input, "\n") | |
instructions := make([]string, 0) | |
for _, line := range lines { | |
if line == "" { | |
continue | |
} | |
if strings.HasPrefix(line, "#") { | |
continue | |
} | |
instructions = append(instructions, line) | |
} | |
return strings.Join(instructions, "\n") | |
} | |
type Int64Value struct { | |
Value int64 | |
} | |
func (i Int64Value) String() string { | |
return fmt.Sprintf("IntValue{Value: %d}", i.Value) | |
} | |
func intValue(v int64) Int64Value { | |
return Int64Value{Value: v} | |
} | |
type BoolValue struct { | |
Value bool | |
} | |
func (i BoolValue) String() string { | |
return fmt.Sprintf("BoolValue{Value: %t}", i.Value) | |
} | |
func boolValue(v bool) BoolValue { | |
return BoolValue{Value: v} | |
} | |
type FunctionCallValue struct { | |
Function string | |
} | |
func (i FunctionCallValue) String() string { | |
return fmt.Sprintf("FunctionCallValue{Function: %s}", i.Function) | |
} | |
func functionCallValue(f string) FunctionCallValue { | |
return FunctionCallValue{Function: f} | |
} | |
type FunctionCallWithConditionalValue struct { | |
Func FunctionCallValue | |
True FunctionCallValue | |
False FunctionCallValue | |
} | |
func (i FunctionCallWithConditionalValue) String() string { | |
return fmt.Sprintf("FunctionCallWithCondiitionalValue{Func: %s, True: %s, False: %s}", i.Func, i.True, i.False) | |
} | |
func functionCallWithConditionalValue(f, trueF, falseF string) FunctionCallWithConditionalValue { | |
return FunctionCallWithConditionalValue{ | |
Func: functionCallValue(f), | |
True: functionCallValue(trueF), | |
False: functionCallValue(falseF), | |
} | |
} | |
type Function func(v []interface{}) interface{} | |
type Block struct { | |
FunctionName string | |
FunctionArgsCount int64 | |
Instructions []interface{} | |
} | |
func newBlock(name string, argsCount int64, instructions []interface{}) Block { | |
return Block{FunctionName: name, FunctionArgsCount: argsCount, Instructions: instructions} | |
} | |
type None struct{} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment