2016-12-16 10:37:42 +00:00
package main
import "log"
import "fmt"
2017-01-17 07:55:46 +00:00
import "bytes"
2016-12-16 10:37:42 +00:00
import "strings"
2016-12-17 03:39:53 +00:00
import "strconv"
2017-01-17 07:55:46 +00:00
//import "regexp"
2016-12-16 10:37:42 +00:00
import "reflect"
import "path/filepath"
import "io/ioutil"
import "text/template/parse"
2017-01-01 15:45:43 +00:00
var ctemplates [ ] string
var tmpl_ptr_map map [ string ] interface { } = make ( map [ string ] interface { } )
2017-02-11 14:51:16 +00:00
var text_overlap_list map [ string ] int
func init ( ) {
text_overlap_list = make ( map [ string ] int )
}
2017-01-01 15:45:43 +00:00
2016-12-16 10:37:42 +00:00
type VarItem struct
{
Name string
Destination string
Type string
}
type VarItemReflect struct
{
Name string
Destination string
Value reflect . Value
}
type CTemplateSet struct
{
tlist map [ string ] * parse . Tree
dir string
funcMap map [ string ] interface { }
importMap map [ string ] string
2017-01-17 07:55:46 +00:00
Fragments map [ string ] int
FragmentCursor map [ string ] int
FragOut string
2016-12-16 10:37:42 +00:00
varList map [ string ] VarItem
localVars map [ string ] map [ string ] VarItemReflect
2016-12-17 03:39:53 +00:00
stats map [ string ] int
pVarList string
pVarPosition int
2016-12-18 12:56:06 +00:00
previousNode parse . NodeType
currentNode parse . NodeType
nextNode parse . NodeType
2016-12-16 10:37:42 +00:00
//tempVars map[string]string
doImports bool
expectsInt interface { }
}
func ( c * CTemplateSet ) compile_template ( name string , dir string , expects string , expectsInt interface { } , varList map [ string ] VarItem ) ( out string ) {
c . dir = dir
c . doImports = true
2017-04-12 10:10:36 +00:00
c . funcMap = map [ string ] interface { } {
"and" : "&&" ,
"not" : "!" ,
"or" : "||" ,
"eq" : true ,
"ge" : true ,
"gt" : true ,
"le" : true ,
"lt" : true ,
"ne" : true ,
"add" : true ,
"subtract" : true ,
"multiply" : true ,
"divide" : true ,
}
c . importMap = map [ string ] string {
"io" : "io" ,
"strconv" : "strconv" ,
}
2016-12-16 10:37:42 +00:00
c . varList = varList
2016-12-17 03:39:53 +00:00
//c.pVarList = ""
//c.pVarPosition = 0
c . stats = make ( map [ string ] int )
2016-12-16 10:37:42 +00:00
c . expectsInt = expectsInt
holdreflect := reflect . ValueOf ( expectsInt )
res , err := ioutil . ReadFile ( dir + name )
if err != nil {
log . Fatal ( err )
}
2017-02-11 14:51:16 +00:00
2016-12-16 10:37:42 +00:00
content := string ( res )
2017-02-11 14:51:16 +00:00
if ! debug {
content = minify ( content )
}
2016-12-16 10:37:42 +00:00
tree := parse . New ( name , c . funcMap )
var treeSet map [ string ] * parse . Tree = make ( map [ string ] * parse . Tree )
tree , err = tree . Parse ( content , "{{" , "}}" , treeSet , c . funcMap )
if err != nil {
log . Fatal ( err )
}
if debug {
fmt . Println ( name )
}
out = ""
fname := strings . TrimSuffix ( name , filepath . Ext ( name ) )
c . tlist = make ( map [ string ] * parse . Tree )
c . tlist [ fname ] = tree
varholder := "tmpl_" + fname + "_vars"
if debug {
fmt . Println ( c . tlist )
}
c . localVars = make ( map [ string ] map [ string ] VarItemReflect )
c . localVars [ fname ] = make ( map [ string ] VarItemReflect )
c . localVars [ fname ] [ "." ] = VarItemReflect { "." , varholder , holdreflect }
2017-01-17 07:55:46 +00:00
if c . Fragments == nil {
c . Fragments = make ( map [ string ] int )
}
c . FragmentCursor = make ( map [ string ] int )
c . FragmentCursor [ fname ] = 0
2016-12-16 10:37:42 +00:00
subtree := c . tlist [ fname ]
if debug {
fmt . Println ( subtree . Root )
}
2016-12-18 12:56:06 +00:00
treeLength := len ( subtree . Root . Nodes )
for index , node := range subtree . Root . Nodes {
2016-12-16 10:37:42 +00:00
if debug {
fmt . Println ( "Node: " + node . String ( ) )
}
2016-12-18 12:56:06 +00:00
c . previousNode = c . currentNode
c . currentNode = node . Type ( )
if treeLength != ( index + 1 ) {
c . nextNode = subtree . Root . Nodes [ index + 1 ] . Type ( )
}
2016-12-16 10:37:42 +00:00
out += c . compile_switch ( varholder , holdreflect , fname , node )
}
var importList string
if c . doImports {
for _ , item := range c . importMap {
importList += "import \"" + item + "\"\n"
}
}
var varString string
for _ , varItem := range c . varList {
varString += "var " + varItem . Name + " " + varItem . Type + " = " + varItem . Destination + "\n"
}
2017-03-27 07:09:28 +00:00
fout := "// Code generated by. DO NOT EDIT.\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n"
2017-01-01 15:45:43 +00:00
fout += "package main\n" + importList + c . pVarList + "\n"
fout += "func init() {\n\ttemplate_" + fname + "_handle = template_" + fname + "\n\t//o_template_" + fname + "_handle = template_" + fname + "\n\tctemplates = append(ctemplates,\"" + fname + "\")\n\ttmpl_ptr_map[\"" + fname + "\"] = &template_" + fname + "_handle\n\ttmpl_ptr_map[\"o_" + fname + "\"] = template_" + fname + "\n}\n\n"
fout += "func template_" + fname + "(tmpl_" + fname + "_vars " + expects + ", w io.Writer) {\n" + varString + out + "}\n"
2016-12-17 03:39:53 +00:00
2017-01-01 15:45:43 +00:00
fout = strings . Replace ( fout , ` ) )
2016-12-17 03:39:53 +00:00
w . Write ( [ ] byte ( ` , " + " , - 1 )
2017-01-01 15:45:43 +00:00
fout = strings . Replace ( fout , "` + `" , "" , - 1 )
2017-01-17 07:55:46 +00:00
//spstr := "`([:space:]*)`"
//whitespace_writes := regexp.MustCompile(`(?s)w.Write\(\[\]byte\(`+spstr+`\)\)`)
//fout = whitespace_writes.ReplaceAllString(fout,"")
2016-12-17 03:39:53 +00:00
for index , count := range c . stats {
fmt . Println ( index + ": " + strconv . Itoa ( count ) )
}
2016-12-18 12:56:06 +00:00
fmt . Println ( " " )
2016-12-17 03:39:53 +00:00
2016-12-16 10:37:42 +00:00
if debug {
fmt . Println ( "Output!" )
2017-01-01 15:45:43 +00:00
fmt . Println ( fout )
2016-12-16 10:37:42 +00:00
}
2017-01-01 15:45:43 +00:00
return fout
2016-12-16 10:37:42 +00:00
}
func ( c * CTemplateSet ) compile_switch ( varholder string , holdreflect reflect . Value , template_name string , node interface { } ) ( out string ) {
switch node := node . ( type ) {
case * parse . ActionNode :
if debug {
fmt . Println ( "Action Node" )
}
if node . Pipe == nil {
break
}
for _ , cmd := range node . Pipe . Cmds {
out += c . compile_subswitch ( varholder , holdreflect , template_name , cmd )
}
return out
case * parse . IfNode :
if debug {
fmt . Println ( "If Node: " )
fmt . Println ( node . Pipe )
}
var expr string
for _ , cmd := range node . Pipe . Cmds {
if debug {
fmt . Println ( "If Node Bit: " )
fmt . Println ( cmd )
fmt . Println ( reflect . ValueOf ( cmd ) . Type ( ) . Name ( ) )
}
expr += c . compile_varswitch ( varholder , holdreflect , template_name , cmd )
}
2016-12-18 12:56:06 +00:00
c . previousNode = c . currentNode
c . currentNode = parse . NodeList
c . nextNode = - 1
2016-12-16 10:37:42 +00:00
if node . ElseList == nil {
if debug {
fmt . Println ( "Branch 1" )
}
return "if " + expr + " {\n" + c . compile_switch ( varholder , holdreflect , template_name , node . List ) + "}\n"
} else {
if debug {
fmt . Println ( "Branch 2" )
}
return "if " + expr + " {\n" + c . compile_switch ( varholder , holdreflect , template_name , node . List ) + "} else {\n" + c . compile_switch ( varholder , holdreflect , template_name , node . ElseList ) + "}\n"
}
case * parse . ListNode :
if debug {
fmt . Println ( "List Node" )
}
for _ , subnode := range node . Nodes {
out += c . compile_switch ( varholder , holdreflect , template_name , subnode )
}
return out
case * parse . RangeNode :
if debug {
fmt . Println ( "Range Node!" )
fmt . Println ( node . Pipe )
}
var outVal reflect . Value
for _ , cmd := range node . Pipe . Cmds {
if debug {
fmt . Println ( "Range Bit: " )
fmt . Println ( cmd )
}
out , outVal = c . compile_reflectswitch ( varholder , holdreflect , template_name , cmd )
}
if debug {
fmt . Println ( "Returned: " )
fmt . Println ( out )
fmt . Println ( "Range Kind Switch!" )
}
switch outVal . Kind ( ) {
case reflect . Map :
var item reflect . Value
for _ , key := range outVal . MapKeys ( ) {
item = outVal . MapIndex ( key )
}
2016-12-21 02:30:32 +00:00
if node . ElseList != nil {
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c . compile_switch ( "item" , item , template_name , node . List ) + "}\n} else {\n" + c . compile_switch ( "item" , item , template_name , node . ElseList ) + "}\n"
} else {
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c . compile_switch ( "item" , item , template_name , node . List ) + "}\n}"
}
2016-12-18 12:56:06 +00:00
case reflect . Slice :
item := outVal . Index ( 0 )
2016-12-16 10:37:42 +00:00
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c . compile_switch ( "item" , item , template_name , node . List ) + "}\n}"
case reflect . Invalid :
return ""
}
if node . ElseList != nil {
out += " else {\n" + c . compile_switch ( varholder , holdreflect , template_name , node . ElseList ) + "}\n"
} else {
out += "\n"
}
return out
case * parse . TemplateNode :
if debug {
fmt . Println ( "Template Node" )
}
return c . compile_subtemplate ( varholder , holdreflect , node )
case * parse . TextNode :
2016-12-18 12:56:06 +00:00
c . previousNode = c . currentNode
c . currentNode = node . Type ( )
c . nextNode = 0
2017-01-17 07:55:46 +00:00
tmpText := bytes . TrimSpace ( node . Text )
if len ( tmpText ) == 0 {
return ""
} else {
//return "w.Write([]byte(`" + string(node.Text) + "`))\n"
fragment_name := template_name + "_" + strconv . Itoa ( c . FragmentCursor [ template_name ] )
_ , ok := c . Fragments [ fragment_name ]
if ! ok {
c . Fragments [ fragment_name ] = len ( node . Text )
c . FragOut += "var " + fragment_name + " []byte = []byte(`" + string ( node . Text ) + "`)\n"
}
c . FragmentCursor [ template_name ] = c . FragmentCursor [ template_name ] + 1
return "w.Write(" + fragment_name + ")\n"
}
2016-12-16 10:37:42 +00:00
default :
panic ( "Unknown Node in main switch" )
}
return ""
}
func ( c * CTemplateSet ) compile_subswitch ( varholder string , holdreflect reflect . Value , template_name string , node * parse . CommandNode ) ( out string ) {
firstWord := node . Args [ 0 ]
switch n := firstWord . ( type ) {
case * parse . FieldNode :
if debug {
fmt . Println ( "Field Node: " )
fmt . Println ( n . Ident )
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
cur := holdreflect
var varbit string
if cur . Kind ( ) == reflect . Interface {
cur = cur . Elem ( )
varbit += ".(" + cur . Type ( ) . Name ( ) + ")"
}
for _ , id := range n . Ident {
if debug {
fmt . Println ( "Data Kind: " )
fmt . Println ( cur . Kind ( ) . String ( ) )
fmt . Println ( "Field Bit: " )
fmt . Println ( id )
}
cur = cur . FieldByName ( id )
if cur . Kind ( ) == reflect . Interface {
cur = cur . Elem ( )
2016-12-17 03:39:53 +00:00
/ * if cur . Kind ( ) == reflect . String && cur . Type ( ) . Name ( ) != "string" {
varbit = "string(" + varbit + "." + id + ")" * /
//if cur.Kind() == reflect.String && cur.Type().Name() != "string" {
2016-12-18 12:56:06 +00:00
if cur . Type ( ) . PkgPath ( ) != "main" && cur . Type ( ) . PkgPath ( ) != "" {
2016-12-17 03:39:53 +00:00
c . importMap [ "html/template" ] = "html/template"
varbit += "." + id + ".(" + strings . TrimPrefix ( cur . Type ( ) . PkgPath ( ) , "html/" ) + "." + cur . Type ( ) . Name ( ) + ")"
2016-12-16 10:37:42 +00:00
} else {
varbit += "." + id + ".(" + cur . Type ( ) . Name ( ) + ")"
}
} else {
varbit += "." + id
}
if debug {
fmt . Println ( "End Cycle" )
}
}
out = c . compile_varsub ( varholder + varbit , cur )
for _ , varItem := range c . varList {
if strings . HasPrefix ( out , varItem . Destination ) {
out = strings . Replace ( out , varItem . Destination , varItem . Name , 1 )
}
}
return out
case * parse . DotNode :
if debug {
fmt . Println ( "Dot Node" )
fmt . Println ( node . String ( ) )
}
return c . compile_varsub ( varholder , holdreflect )
case * parse . NilNode :
panic ( "Nil is not a command x.x" )
case * parse . VariableNode :
if debug {
fmt . Println ( "Variable Node" )
fmt . Println ( n . String ( ) )
fmt . Println ( n . Ident )
}
2017-01-12 02:55:08 +00:00
varname , reflectVal := c . compile_if_varsub ( n . String ( ) , varholder , template_name , holdreflect )
return c . compile_varsub ( varname , reflectVal )
2016-12-16 10:37:42 +00:00
case * parse . StringNode :
return n . Quoted
2017-01-21 18:16:27 +00:00
case * parse . IdentifierNode :
if debug {
fmt . Println ( "Identifier Node: " )
fmt . Println ( node )
fmt . Println ( node . Args )
}
return c . compile_varsub ( c . compile_identswitch ( varholder , holdreflect , template_name , node ) )
2016-12-16 10:37:42 +00:00
default :
fmt . Println ( "Unknown Kind: " )
fmt . Println ( reflect . ValueOf ( firstWord ) . Elem ( ) . Kind ( ) )
fmt . Println ( "Unknown Type: " )
fmt . Println ( reflect . ValueOf ( firstWord ) . Elem ( ) . Type ( ) . Name ( ) )
panic ( "I don't know what node this is" )
}
return ""
}
func ( c * CTemplateSet ) compile_varswitch ( varholder string , holdreflect reflect . Value , template_name string , node * parse . CommandNode ) ( out string ) {
firstWord := node . Args [ 0 ]
switch n := firstWord . ( type ) {
case * parse . FieldNode :
if debug {
fmt . Println ( "Field Node: " )
fmt . Println ( n . Ident )
for _ , id := range n . Ident {
fmt . Println ( "Field Bit: " )
fmt . Println ( id )
}
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
return c . compile_boolsub ( n . String ( ) , varholder , template_name , holdreflect )
case * parse . ChainNode :
if debug {
fmt . Println ( "Chain Node: " )
fmt . Println ( n . Node )
fmt . Println ( node . Args )
}
break
case * parse . IdentifierNode :
if debug {
fmt . Println ( "Identifier Node: " )
fmt . Println ( node )
fmt . Println ( node . Args )
}
2017-01-21 18:16:27 +00:00
return c . compile_identswitch_n ( varholder , holdreflect , template_name , node )
2016-12-16 10:37:42 +00:00
case * parse . DotNode :
return varholder
case * parse . VariableNode :
if debug {
fmt . Println ( "Variable Node" )
fmt . Println ( n . String ( ) )
fmt . Println ( n . Ident )
}
out , _ = c . compile_if_varsub ( n . String ( ) , varholder , template_name , holdreflect )
return out
case * parse . NilNode :
panic ( "Nil is not a command x.x" )
case * parse . PipeNode :
if debug {
fmt . Println ( "Pipe Node!" )
fmt . Println ( n )
fmt . Println ( "Args: " )
fmt . Println ( node . Args )
}
2017-01-21 18:16:27 +00:00
out += c . compile_identswitch_n ( varholder , holdreflect , template_name , node )
2016-12-16 10:37:42 +00:00
if debug {
fmt . Println ( "Out: " )
fmt . Println ( out )
}
return out
default :
fmt . Println ( "Unknown Kind: " )
fmt . Println ( reflect . ValueOf ( firstWord ) . Elem ( ) . Kind ( ) )
fmt . Println ( "Unknown Type: " )
fmt . Println ( reflect . ValueOf ( firstWord ) . Elem ( ) . Type ( ) . Name ( ) )
panic ( "I don't know what node this is! Grr..." )
}
return ""
}
2017-01-21 18:16:27 +00:00
func ( c * CTemplateSet ) compile_identswitch_n ( varholder string , holdreflect reflect . Value , template_name string , node * parse . CommandNode ) ( out string ) {
out , _ = c . compile_identswitch ( varholder , holdreflect , template_name , node )
return out
}
func ( c * CTemplateSet ) compile_identswitch ( varholder string , holdreflect reflect . Value , template_name string , node * parse . CommandNode ) ( out string , val reflect . Value ) {
2016-12-16 10:37:42 +00:00
ArgLoop :
for pos , id := range node . Args {
if debug {
fmt . Println ( id )
}
switch id . String ( ) {
case "not" :
out += "!"
case "or" :
out += " || "
case "and" :
out += " && "
case "le" :
out += c . compile_if_varsub_n ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect ) + " <= " + c . compile_if_varsub_n ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
2017-01-21 18:16:27 +00:00
if debug {
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
2016-12-16 10:37:42 +00:00
break ArgLoop
2017-01-12 02:55:08 +00:00
case "lt" :
out += c . compile_if_varsub_n ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect ) + " < " + c . compile_if_varsub_n ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
2017-01-21 18:16:27 +00:00
if debug {
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
2017-01-12 02:55:08 +00:00
break ArgLoop
case "gt" :
out += c . compile_if_varsub_n ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect ) + " > " + c . compile_if_varsub_n ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
2017-01-21 18:16:27 +00:00
if debug {
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
2017-01-12 02:55:08 +00:00
break ArgLoop
case "ge" :
out += c . compile_if_varsub_n ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect ) + " >= " + c . compile_if_varsub_n ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
2017-01-21 18:16:27 +00:00
if debug {
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
2017-01-12 02:55:08 +00:00
break ArgLoop
case "eq" :
out += c . compile_if_varsub_n ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect ) + " == " + c . compile_if_varsub_n ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
2017-01-21 18:16:27 +00:00
if debug {
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
2017-01-12 02:55:08 +00:00
break ArgLoop
case "ne" :
out += c . compile_if_varsub_n ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect ) + " != " + c . compile_if_varsub_n ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
2017-01-21 18:16:27 +00:00
if debug {
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
break ArgLoop
case "add" :
param1 , val2 := c . compile_if_varsub ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect )
param2 , val3 := c . compile_if_varsub ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
if val2 . IsValid ( ) {
val = val2
} else if val3 . IsValid ( ) {
val = val3
} else {
numSample := 1
val = reflect . ValueOf ( numSample )
}
out += param1 + " + " + param2
if debug {
fmt . Println ( "add" )
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
break ArgLoop
case "subtract" :
param1 , val2 := c . compile_if_varsub ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect )
param2 , val3 := c . compile_if_varsub ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
if val2 . IsValid ( ) {
val = val2
} else if val3 . IsValid ( ) {
val = val3
} else {
numSample := 1
val = reflect . ValueOf ( numSample )
}
out += param1 + " - " + param2
if debug {
fmt . Println ( "subtract" )
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
break ArgLoop
case "divide" :
param1 , val2 := c . compile_if_varsub ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect )
param2 , val3 := c . compile_if_varsub ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
if val2 . IsValid ( ) {
val = val2
} else if val3 . IsValid ( ) {
val = val3
} else {
numSample := 1
val = reflect . ValueOf ( numSample )
}
out += param1 + " / " + param2
if debug {
fmt . Println ( "divide" )
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
break ArgLoop
case "multiply" :
param1 , val2 := c . compile_if_varsub ( node . Args [ pos + 1 ] . String ( ) , varholder , template_name , holdreflect )
param2 , val3 := c . compile_if_varsub ( node . Args [ pos + 2 ] . String ( ) , varholder , template_name , holdreflect )
if val2 . IsValid ( ) {
val = val2
} else if val3 . IsValid ( ) {
val = val3
} else {
numSample := 1
val = reflect . ValueOf ( numSample )
}
out += param1 + " * " + param2
if debug {
fmt . Println ( "multiply" )
fmt . Println ( node . Args [ pos + 1 ] )
fmt . Println ( node . Args [ pos + 2 ] )
}
2017-01-12 02:55:08 +00:00
break ArgLoop
2016-12-16 10:37:42 +00:00
default :
if debug {
fmt . Println ( "Variable!" )
}
out += c . compile_if_varsub_n ( id . String ( ) , varholder , template_name , holdreflect )
}
}
2017-01-21 18:16:27 +00:00
return out , val
2016-12-16 10:37:42 +00:00
}
func ( c * CTemplateSet ) compile_reflectswitch ( varholder string , holdreflect reflect . Value , template_name string , node * parse . CommandNode ) ( out string , outVal reflect . Value ) {
firstWord := node . Args [ 0 ]
switch n := firstWord . ( type ) {
case * parse . FieldNode :
if debug {
fmt . Println ( "Field Node: " )
fmt . Println ( n . Ident )
for _ , id := range n . Ident {
fmt . Println ( "Field Bit: " )
fmt . Println ( id )
}
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
return c . compile_if_varsub ( n . String ( ) , varholder , template_name , holdreflect )
case * parse . ChainNode :
if debug {
fmt . Println ( "Chain Node: " )
fmt . Println ( n . Node )
fmt . Println ( node . Args )
}
return "" , outVal
case * parse . DotNode :
return varholder , holdreflect
case * parse . NilNode :
panic ( "Nil is not a command x.x" )
default :
//panic("I don't know what node this is")
}
return "" , outVal
}
func ( c * CTemplateSet ) compile_if_varsub_n ( varname string , varholder string , template_name string , cur reflect . Value ) ( out string ) {
out , _ = c . compile_if_varsub ( varname , varholder , template_name , cur )
return out
}
func ( c * CTemplateSet ) compile_if_varsub ( varname string , varholder string , template_name string , cur reflect . Value ) ( out string , val reflect . Value ) {
if varname [ 0 ] != '.' && varname [ 0 ] != '$' {
return varname , cur
}
bits := strings . Split ( varname , "." )
if varname [ 0 ] == '$' {
var res VarItemReflect
if varname [ 1 ] == '.' {
res = c . localVars [ template_name ] [ "." ]
} else {
res = c . localVars [ template_name ] [ strings . TrimPrefix ( bits [ 0 ] , "$" ) ]
}
out += res . Destination
cur = res . Value
if cur . Kind ( ) == reflect . Interface {
cur = cur . Elem ( )
}
} else {
if cur . Kind ( ) == reflect . Interface {
cur = cur . Elem ( )
out += varholder + ".(" + cur . Type ( ) . Name ( ) + ")"
} else {
out += varholder
}
}
bits [ 0 ] = strings . TrimPrefix ( bits [ 0 ] , "$" )
if debug {
fmt . Println ( "Cur Kind: " )
fmt . Println ( cur . Kind ( ) )
fmt . Println ( "Cur Type: " )
fmt . Println ( cur . Type ( ) . Name ( ) )
}
for _ , bit := range bits {
if debug {
fmt . Println ( "Variable Field!" )
fmt . Println ( bit )
}
if bit == "" {
continue
}
cur = cur . FieldByName ( bit )
if cur . Kind ( ) == reflect . Interface {
cur = cur . Elem ( )
out += "." + bit + ".(" + cur . Type ( ) . Name ( ) + ")"
} else {
out += "." + bit
}
if debug {
fmt . Println ( "Data Kind: " )
fmt . Println ( cur . Kind ( ) )
fmt . Println ( "Data Type: " )
fmt . Println ( cur . Type ( ) . Name ( ) )
}
}
2017-01-21 18:16:27 +00:00
if debug {
fmt . Println ( "Out Value: " )
fmt . Println ( out )
fmt . Println ( "Out Kind: " )
fmt . Println ( cur . Kind ( ) )
fmt . Println ( "Out Type: " )
fmt . Println ( cur . Type ( ) . Name ( ) )
}
2016-12-16 10:37:42 +00:00
for _ , varItem := range c . varList {
if strings . HasPrefix ( out , varItem . Destination ) {
out = strings . Replace ( out , varItem . Destination , varItem . Name , 1 )
}
}
2016-12-17 03:39:53 +00:00
2017-01-21 18:16:27 +00:00
if debug {
fmt . Println ( "Out Value: " )
fmt . Println ( out )
fmt . Println ( "Out Kind: " )
fmt . Println ( cur . Kind ( ) )
fmt . Println ( "Out Type: " )
fmt . Println ( cur . Type ( ) . Name ( ) )
}
2016-12-17 03:39:53 +00:00
_ , ok := c . stats [ out ]
if ok {
c . stats [ out ] ++
} else {
c . stats [ out ] = 1
}
2016-12-16 10:37:42 +00:00
return out , cur
}
func ( c * CTemplateSet ) compile_boolsub ( varname string , varholder string , template_name string , val reflect . Value ) string {
out , val := c . compile_if_varsub ( varname , varholder , template_name , val )
switch val . Kind ( ) {
2017-03-03 16:28:49 +00:00
case reflect . Int : out += " > 0"
case reflect . Bool : // Do nothing
case reflect . String : out += " != \"\""
case reflect . Int64 : out += " > 0"
2016-12-16 10:37:42 +00:00
default :
2017-01-21 18:16:27 +00:00
fmt . Println ( varname )
fmt . Println ( varholder )
fmt . Println ( val . Kind ( ) )
2016-12-16 10:37:42 +00:00
panic ( "I don't know what this variable's type is o.o\n" )
}
return out
}
func ( c * CTemplateSet ) compile_varsub ( varname string , val reflect . Value ) string {
for _ , varItem := range c . varList {
if strings . HasPrefix ( varname , varItem . Destination ) {
varname = strings . Replace ( varname , varItem . Destination , varItem . Name , 1 )
}
}
2016-12-17 03:39:53 +00:00
_ , ok := c . stats [ varname ]
if ok {
c . stats [ varname ] ++
} else {
c . stats [ varname ] = 1
}
2016-12-16 10:37:42 +00:00
if val . Kind ( ) == reflect . Interface {
val = val . Elem ( )
}
switch val . Kind ( ) {
case reflect . Int :
2016-12-17 03:39:53 +00:00
return "w.Write([]byte(strconv.Itoa(" + varname + ")))\n"
2016-12-16 10:37:42 +00:00
case reflect . Bool :
2016-12-17 03:39:53 +00:00
return "if " + varname + " {\nw.Write([]byte(\"true\"))} else {\nw.Write([]byte(\"false\"))\n}\n"
2016-12-16 10:37:42 +00:00
case reflect . String :
2016-12-17 03:39:53 +00:00
if val . Type ( ) . Name ( ) != "string" && ! strings . HasPrefix ( varname , "string(" ) {
return "w.Write([]byte(string(" + varname + ")))\n"
2016-12-16 10:37:42 +00:00
} else {
2016-12-17 03:39:53 +00:00
return "w.Write([]byte(" + varname + "))\n"
2016-12-16 10:37:42 +00:00
}
case reflect . Int64 :
2016-12-17 03:39:53 +00:00
return "w.Write([]byte(strconv.FormatInt(" + varname + ", 10)))"
2016-12-16 10:37:42 +00:00
default :
2017-01-21 18:16:27 +00:00
fmt . Println ( "Unknown Variable Name: " )
fmt . Println ( varname )
2016-12-16 10:37:42 +00:00
fmt . Println ( "Unknown Kind: " )
fmt . Println ( val . Kind ( ) )
fmt . Println ( "Unknown Type: " )
fmt . Println ( val . Type ( ) . Name ( ) )
panic ( "// I don't know what this variable's type is o.o\n" )
}
}
func ( c * CTemplateSet ) compile_subtemplate ( pvarholder string , pholdreflect reflect . Value , node * parse . TemplateNode ) ( out string ) {
if debug {
fmt . Println ( "Template Node: " + node . Name )
}
fname := strings . TrimSuffix ( node . Name , filepath . Ext ( node . Name ) )
varholder := "tmpl_" + fname + "_vars"
var holdreflect reflect . Value
if node . Pipe != nil {
for _ , cmd := range node . Pipe . Cmds {
firstWord := cmd . Args [ 0 ]
switch firstWord . ( type ) {
case * parse . DotNode :
varholder = pvarholder
holdreflect = pholdreflect
break
case * parse . NilNode :
panic ( "Nil is not a command x.x" )
default :
out = "var " + varholder + " := false\n"
out += c . compile_command ( cmd )
}
}
}
res , err := ioutil . ReadFile ( c . dir + node . Name )
if err != nil {
log . Fatal ( err )
}
2017-02-11 14:51:16 +00:00
2016-12-16 10:37:42 +00:00
content := string ( res )
2017-02-11 14:51:16 +00:00
if ! debug {
content = minify ( content )
}
2016-12-16 10:37:42 +00:00
tree := parse . New ( node . Name , c . funcMap )
var treeSet map [ string ] * parse . Tree = make ( map [ string ] * parse . Tree )
tree , err = tree . Parse ( content , "{{" , "}}" , treeSet , c . funcMap )
if err != nil {
log . Fatal ( err )
}
c . tlist [ fname ] = tree
subtree := c . tlist [ fname ]
if debug {
fmt . Println ( subtree . Root )
}
c . localVars [ fname ] = make ( map [ string ] VarItemReflect )
c . localVars [ fname ] [ "." ] = VarItemReflect { "." , varholder , holdreflect }
2017-01-17 07:55:46 +00:00
c . FragmentCursor [ fname ] = 0
2016-12-16 10:37:42 +00:00
2016-12-18 12:56:06 +00:00
treeLength := len ( subtree . Root . Nodes )
for index , node := range subtree . Root . Nodes {
2016-12-16 10:37:42 +00:00
if debug {
fmt . Println ( "Node: " + node . String ( ) )
}
2016-12-18 12:56:06 +00:00
c . previousNode = c . currentNode
c . currentNode = node . Type ( )
if treeLength != ( index + 1 ) {
c . nextNode = subtree . Root . Nodes [ index + 1 ] . Type ( )
}
2016-12-16 10:37:42 +00:00
out += c . compile_switch ( varholder , holdreflect , fname , node )
}
return out
}
func ( c * CTemplateSet ) compile_command ( * parse . CommandNode ) ( out string ) {
2017-02-15 10:49:30 +00:00
panic ( "Uh oh! Something went wrong!" )
2016-12-16 10:37:42 +00:00
return ""
2017-02-11 14:51:16 +00:00
}
func minify ( data string ) string {
data = strings . Replace ( data , "\t" , "" , - 1 )
data = strings . Replace ( data , "\v" , "" , - 1 )
data = strings . Replace ( data , "\n" , "" , - 1 )
data = strings . Replace ( data , "\r" , "" , - 1 )
data = strings . Replace ( data , " " , " " , - 1 )
return data
}