2016-12-16 10:37:42 +00:00
package main
2017-05-07 08:31:41 +00:00
2017-06-05 11:57:27 +00:00
import (
"bytes"
2017-09-03 04:50:31 +00:00
"fmt"
"log"
2017-06-05 11:57:27 +00:00
"strconv"
2017-09-03 04:50:31 +00:00
"strings"
2017-06-05 11:57:27 +00:00
//"regexp"
"io/ioutil"
2017-09-03 04:50:31 +00:00
"path/filepath"
"reflect"
2017-06-05 11:57:27 +00:00
"text/template/parse"
)
2016-12-16 10:37:42 +00:00
2017-09-10 16:57:22 +00:00
// TODO: Turn this file into a library
2017-01-01 15:45:43 +00:00
var ctemplates [ ] string
2017-09-03 04:50:31 +00:00
var tmplPtrMap = make ( map [ string ] interface { } )
var textOverlapList = make ( map [ string ] int )
2017-01-01 15:45:43 +00:00
2017-09-03 04:50:31 +00:00
// nolint
type VarItem struct {
Name string
2016-12-16 10:37:42 +00:00
Destination string
2017-09-03 04:50:31 +00:00
Type string
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
type VarItemReflect struct {
Name string
2016-12-16 10:37:42 +00:00
Destination string
2017-09-03 04:50:31 +00:00
Value reflect . Value
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
type CTemplateSet struct {
tlist map [ string ] * parse . Tree
dir string
funcMap map [ string ] interface { }
importMap map [ string ] string
Fragments map [ string ] int
2017-01-17 07:55:46 +00:00
FragmentCursor map [ string ] int
2017-09-03 04:50:31 +00:00
FragOut string
varList map [ string ] VarItem
localVars map [ string ] map [ string ] VarItemReflect
stats map [ string ] int
pVarList string
pVarPosition int
previousNode parse . NodeType
currentNode parse . NodeType
nextNode parse . NodeType
2016-12-16 10:37:42 +00:00
//tempVars map[string]string
2017-09-03 04:50:31 +00:00
doImports bool
2016-12-16 10:37:42 +00:00
expectsInt interface { }
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileTemplate ( name string , dir string , expects string , expectsInt interface { } , varList map [ string ] VarItem ) ( out string , err error ) {
2017-08-06 15:22:18 +00:00
if dev . DebugMode {
fmt . Println ( "Compiling template '" + name + "'" )
}
2016-12-16 10:37:42 +00:00
c . dir = dir
c . doImports = true
2017-04-12 10:10:36 +00:00
c . funcMap = map [ string ] interface { } {
2017-09-03 04:50:31 +00:00
"and" : "&&" ,
"not" : "!" ,
"or" : "||" ,
"eq" : true ,
"ge" : true ,
"gt" : true ,
"le" : true ,
"lt" : true ,
"ne" : true ,
"add" : true ,
2017-04-12 10:10:36 +00:00
"subtract" : true ,
"multiply" : true ,
2017-09-03 04:50:31 +00:00
"divide" : true ,
2017-04-12 10:10:36 +00:00
}
2017-06-16 10:41:30 +00:00
2017-04-12 10:10:36 +00:00
c . importMap = map [ string ] string {
2017-09-03 04:50:31 +00:00
"net/http" : "net/http" ,
2017-04-12 10:10:36 +00:00
}
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 )
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
res , err := ioutil . ReadFile ( dir + name )
if err != nil {
2017-08-13 11:22:34 +00:00
return "" , err
2016-12-16 10:37:42 +00:00
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
content := string ( res )
2017-07-17 10:23:42 +00:00
if config . MinifyTemplates {
2017-02-11 14:51:16 +00:00
content = minify ( content )
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
tree := parse . New ( name , c . funcMap )
2017-09-03 04:50:31 +00:00
var treeSet = make ( map [ string ] * parse . Tree )
tree , err = tree . Parse ( content , "{{" , "}}" , treeSet , c . funcMap )
2016-12-16 10:37:42 +00:00
if err != nil {
2017-08-13 11:22:34 +00:00
return "" , err
2016-12-16 10:37:42 +00:00
}
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2016-12-16 10:37:42 +00:00
fmt . Println ( name )
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
out = ""
fname := strings . TrimSuffix ( name , filepath . Ext ( name ) )
c . tlist = make ( map [ string ] * parse . Tree )
c . tlist [ fname ] = tree
varholder := "tmpl_" + fname + "_vars"
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2016-12-16 10:37:42 +00:00
fmt . Println ( c . tlist )
}
c . localVars = make ( map [ string ] map [ string ] VarItemReflect )
c . localVars [ fname ] = make ( map [ string ] VarItemReflect )
2017-09-03 04:50:31 +00:00
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
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
subtree := c . tlist [ fname ]
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2016-12-16 10:37:42 +00:00
fmt . Println ( subtree . Root )
}
2017-06-16 10:41:30 +00:00
2016-12-18 12:56:06 +00:00
treeLength := len ( subtree . Root . Nodes )
for index , node := range subtree . Root . Nodes {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2016-12-16 10:37:42 +00:00
fmt . Println ( "Node: " + node . String ( ) )
}
2017-06-16 10:41:30 +00:00
2016-12-18 12:56:06 +00:00
c . previousNode = c . currentNode
c . currentNode = node . Type ( )
if treeLength != ( index + 1 ) {
2017-09-03 04:50:31 +00:00
c . nextNode = subtree . Root . Nodes [ index + 1 ] . Type ( )
2016-12-18 12:56:06 +00:00
}
2017-09-03 04:50:31 +00:00
out += c . compileSwitch ( varholder , holdreflect , fname , node )
2016-12-16 10:37:42 +00:00
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
var importList string
if c . doImports {
for _ , item := range c . importMap {
importList += "import \"" + item + "\"\n"
}
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
var varString string
for _ , varItem := range c . varList {
varString += "var " + varItem . Name + " " + varItem . Type + " = " + varItem . Destination + "\n"
}
2017-06-16 10:41:30 +00:00
2017-08-13 11:22:34 +00:00
fout := "// +build !no_templategen\n\n// Code generated by Gosora. More below:\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n"
fout += "package main\n" + importList + c . pVarList + "\n"
2017-09-03 04:50:31 +00:00
fout += "// nolint\nfunc init() {\n\ttemplate_" + fname + "_handle = template_" + fname + "\n\t//o_template_" + fname + "_handle = template_" + fname + "\n\tctemplates = append(ctemplates,\"" + fname + "\")\n\ttmplPtrMap[\"" + fname + "\"] = &template_" + fname + "_handle\n\ttmplPtrMap[\"o_" + fname + "\"] = template_" + fname + "\n}\n\n"
fout += "// nolint\nfunc template_" + fname + "(tmpl_" + fname + "_vars " + expects + ", w http.ResponseWriter) {\n" + varString + out + "}\n"
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
fout = strings . Replace ( fout , ` ) )
w . Write ( [ ] byte ( ` , " + " , - 1 )
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,"")
2017-06-16 10:41:30 +00:00
2017-07-17 10:23:42 +00:00
if dev . DebugMode {
2017-05-07 08:31:41 +00:00
for index , count := range c . stats {
fmt . Println ( index + ": " + strconv . Itoa ( count ) )
}
fmt . Println ( " " )
2016-12-17 03:39:53 +00:00
}
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2016-12-16 10:37:42 +00:00
fmt . Println ( "Output!" )
2017-01-01 15:45:43 +00:00
fmt . Println ( fout )
2016-12-16 10:37:42 +00:00
}
2017-08-13 11:22:34 +00:00
return fout , nil
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileSwitch ( varholder string , holdreflect reflect . Value , templateName string , node interface { } ) ( out string ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileSwitch" )
2017-06-05 11:57:27 +00:00
}
2016-12-16 10:37:42 +00:00
switch node := node . ( type ) {
2017-09-03 04:50:31 +00:00
case * parse . ActionNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Action Node" )
}
if node . Pipe == nil {
break
}
for _ , cmd := range node . Pipe . Cmds {
out += c . compileSubswitch ( varholder , holdreflect , templateName , cmd )
}
return out
case * parse . IfNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "If Node:" )
fmt . Println ( "node.Pipe" , node . Pipe )
}
var expr string
for _ , cmd := range node . Pipe . Cmds {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "If Node Bit:" , cmd )
fmt . Println ( "If Node Bit Type:" , reflect . ValueOf ( cmd ) . Type ( ) . Name ( ) )
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
expr += c . compileVarswitch ( varholder , holdreflect , templateName , cmd )
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "If Node Expression Step:" , c . compileVarswitch ( varholder , holdreflect , templateName , cmd ) )
2017-06-05 11:57:27 +00:00
}
2017-09-03 04:50:31 +00:00
}
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "If Node Expression:" , expr )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
c . previousNode = c . currentNode
c . currentNode = parse . NodeList
c . nextNode = - 1
if node . ElseList == nil {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Selected Branch 1" )
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
return "if " + expr + " {\n" + c . compileSwitch ( varholder , holdreflect , templateName , node . List ) + "}\n"
}
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Selected Branch 2" )
}
return "if " + expr + " {\n" + c . compileSwitch ( varholder , holdreflect , templateName , node . List ) + "} else {\n" + c . compileSwitch ( varholder , holdreflect , templateName , node . ElseList ) + "}\n"
case * parse . ListNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "List Node" )
}
for _ , subnode := range node . Nodes {
out += c . compileSwitch ( varholder , holdreflect , templateName , subnode )
}
return out
case * parse . RangeNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Range Node!" )
fmt . Println ( node . Pipe )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
var outVal reflect . Value
for _ , cmd := range node . Pipe . Cmds {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Range Bit:" , cmd )
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
out , outVal = c . compileReflectswitch ( varholder , holdreflect , templateName , cmd )
}
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Returned:" , out )
fmt . Println ( "Range Kind Switch!" )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
switch outVal . Kind ( ) {
case reflect . Map :
var item reflect . Value
for _ , key := range outVal . MapKeys ( ) {
item = outVal . MapIndex ( key )
2016-12-16 10:37:42 +00:00
}
2017-09-10 16:57:22 +00:00
fmt . Println ( "Range item:" , item )
if ! item . IsValid ( ) {
panic ( "item" + "^\n" + "Invalid map. Maybe, it doesn't have any entries for the template engine to analyse?" )
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
if node . ElseList != nil {
2017-09-03 04:50:31 +00:00
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c . compileSwitch ( "item" , item , templateName , node . List ) + "}\n} else {\n" + c . compileSwitch ( "item" , item , templateName , node . ElseList ) + "}\n"
2016-12-16 10:37:42 +00:00
} else {
2017-09-03 04:50:31 +00:00
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c . compileSwitch ( "item" , item , templateName , node . List ) + "}\n}"
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
case reflect . Slice :
if outVal . Len ( ) == 0 {
panic ( "The sample data needs at-least one or more elements for the slices. We're looking into removing this requirement at some point!" )
2017-01-17 07:55:46 +00:00
}
2017-09-03 04:50:31 +00:00
item := outVal . Index ( 0 )
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c . compileSwitch ( "item" , item , templateName , node . List ) + "}\n}"
case reflect . Invalid :
return ""
}
if node . ElseList != nil {
out += " else {\n" + c . compileSwitch ( varholder , holdreflect , templateName , node . ElseList ) + "}\n"
} else {
out += "\n"
}
return out
case * parse . TemplateNode :
return c . compileSubtemplate ( varholder , holdreflect , node )
case * parse . TextNode :
c . previousNode = c . currentNode
c . currentNode = node . Type ( )
c . nextNode = 0
tmpText := bytes . TrimSpace ( node . Text )
if len ( tmpText ) == 0 {
return ""
}
//return "w.Write([]byte(`" + string(node.Text) + "`))\n"
fragmentName := templateName + "_" + strconv . Itoa ( c . FragmentCursor [ templateName ] )
_ , ok := c . Fragments [ fragmentName ]
if ! ok {
c . Fragments [ fragmentName ] = len ( node . Text )
c . FragOut += "var " + fragmentName + " = []byte(`" + string ( node . Text ) + "`)\n"
}
c . FragmentCursor [ templateName ] = c . FragmentCursor [ templateName ] + 1
return "w.Write(" + fragmentName + ")\n"
default :
panic ( "Unknown Node in main switch" )
2016-12-16 10:37:42 +00:00
}
return ""
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileSubswitch ( varholder string , holdreflect reflect . Value , templateName string , node * parse . CommandNode ) ( out string ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileSubswitch" )
2017-06-05 11:57:27 +00:00
}
2016-12-16 10:37:42 +00:00
firstWord := node . Args [ 0 ]
switch n := firstWord . ( type ) {
2017-09-03 04:50:31 +00:00
case * parse . FieldNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Field Node:" , n . Ident )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Variable declarations are coming soon! */
cur := holdreflect
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
var varbit string
if cur . Kind ( ) == reflect . Interface {
cur = cur . Elem ( )
varbit += ".(" + cur . Type ( ) . Name ( ) + ")"
}
for _ , id := range n . Ident {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Data Kind:" , cur . Kind ( ) . String ( ) )
fmt . Println ( "Field Bit:" , id )
2016-12-16 10:37:42 +00:00
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
if cur . Kind ( ) == reflect . Ptr {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Looping over pointer" )
2017-07-17 10:23:42 +00:00
}
2017-09-03 04:50:31 +00:00
for cur . Kind ( ) == reflect . Ptr {
2016-12-16 10:37:42 +00:00
cur = cur . Elem ( )
}
2017-09-03 04:50:31 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Data Kind:" , cur . Kind ( ) . String ( ) )
fmt . Println ( "Field Bit:" , id )
2016-12-16 10:37:42 +00:00
}
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
if ! cur . IsValid ( ) {
2017-09-10 16:57:22 +00:00
if dev . DebugMode {
fmt . Println ( "Debug Data:" )
fmt . Println ( "Holdreflect:" , holdreflect )
fmt . Println ( "Holdreflect.Kind()" , holdreflect . Kind ( ) )
2017-09-23 21:28:50 +00:00
if ! dev . TemplateDebug {
2017-09-10 16:57:22 +00:00
fmt . Println ( "cur.Kind():" , cur . Kind ( ) . String ( ) )
}
fmt . Println ( "" )
}
2017-09-03 04:50:31 +00:00
panic ( varholder + varbit + "^\n" + "Invalid value. Maybe, it doesn't exist?" )
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
cur = cur . FieldByName ( id )
if cur . Kind ( ) == reflect . Interface {
cur = cur . Elem ( )
2017-09-10 16:57:22 +00:00
// TODO: Surely, there's a better way of detecting this?
2017-09-03 04:50:31 +00:00
/ * if cur . Kind ( ) == reflect . String && cur . Type ( ) . Name ( ) != "string" {
varbit = "string(" + varbit + "." + id + ")" * /
//if cur.Kind() == reflect.String && cur.Type().Name() != "string" {
if cur . Type ( ) . PkgPath ( ) != "main" && cur . Type ( ) . PkgPath ( ) != "" {
c . importMap [ "html/template" ] = "html/template"
varbit += "." + id + ".(" + strings . TrimPrefix ( cur . Type ( ) . PkgPath ( ) , "html/" ) + "." + cur . Type ( ) . Name ( ) + ")"
} else {
varbit += "." + id + ".(" + cur . Type ( ) . Name ( ) + ")"
}
} else {
varbit += "." + id
2016-12-16 10:37:42 +00:00
}
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "End Cycle" )
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
}
out = c . compileVarsub ( varholder + varbit , cur )
for _ , varItem := range c . varList {
if strings . HasPrefix ( out , varItem . Destination ) {
out = strings . Replace ( out , varItem . Destination , varItem . Name , 1 )
2017-01-21 18:16:27 +00:00
}
2017-09-03 04:50:31 +00:00
}
return out
case * parse . DotNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Dot Node:" , node . String ( ) )
}
return c . compileVarsub ( varholder , holdreflect )
case * parse . NilNode :
panic ( "Nil is not a command x.x" )
case * parse . VariableNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Variable Node:" , n . String ( ) )
fmt . Println ( n . Ident )
}
varname , reflectVal := c . compileIfVarsub ( n . String ( ) , varholder , templateName , holdreflect )
return c . compileVarsub ( varname , reflectVal )
case * parse . StringNode :
return n . Quoted
case * parse . IdentifierNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Identifier Node:" , node )
fmt . Println ( "Identifier Node Args:" , node . Args )
}
return c . compileVarsub ( c . compileIdentswitch ( varholder , holdreflect , templateName , node ) )
default :
fmt . Println ( "Unknown Kind:" , reflect . ValueOf ( firstWord ) . Elem ( ) . Kind ( ) )
fmt . Println ( "Unknown Type:" , reflect . ValueOf ( firstWord ) . Elem ( ) . Type ( ) . Name ( ) )
panic ( "I don't know what node this is" )
2016-12-16 10:37:42 +00:00
}
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileVarswitch ( varholder string , holdreflect reflect . Value , templateName string , node * parse . CommandNode ) ( out string ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-06-05 11:57:27 +00:00
fmt . Println ( "in compile_varswitch" )
}
2016-12-16 10:37:42 +00:00
firstWord := node . Args [ 0 ]
switch n := firstWord . ( type ) {
2017-09-03 04:50:31 +00:00
case * parse . FieldNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Field Node:" , n . Ident )
for _ , id := range n . Ident {
fmt . Println ( "Field Bit:" , id )
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
return c . compileBoolsub ( n . String ( ) , varholder , templateName , holdreflect )
case * parse . ChainNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Chain Node:" , n . Node )
fmt . Println ( "Chain Node Args:" , node . Args )
}
break
case * parse . IdentifierNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Identifier Node:" , node )
fmt . Println ( "Identifier Node Args:" , node . Args )
}
return c . compileIdentswitchN ( varholder , holdreflect , templateName , node )
case * parse . DotNode :
return varholder
case * parse . VariableNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Variable Node:" , n . String ( ) )
fmt . Println ( "Variable Node Identifier:" , n . Ident )
}
out , _ = c . compileIfVarsub ( n . String ( ) , varholder , templateName , holdreflect )
return out
case * parse . NilNode :
panic ( "Nil is not a command x.x" )
case * parse . PipeNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Pipe Node!" )
fmt . Println ( n )
fmt . Println ( "Args:" , node . Args )
}
out += c . compileIdentswitchN ( varholder , holdreflect , templateName , node )
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Out:" , out )
}
return out
default :
fmt . Println ( "Unknown Kind:" , reflect . ValueOf ( firstWord ) . Elem ( ) . Kind ( ) )
fmt . Println ( "Unknown Type:" , reflect . ValueOf ( firstWord ) . Elem ( ) . Type ( ) . Name ( ) )
panic ( "I don't know what node this is! Grr..." )
2016-12-16 10:37:42 +00:00
}
return ""
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileIdentswitchN ( varholder string , holdreflect reflect . Value , templateName string , node * parse . CommandNode ) ( out string ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-06-05 11:57:27 +00:00
fmt . Println ( "in compile_identswitch_n" )
}
2017-09-03 04:50:31 +00:00
out , _ = c . compileIdentswitch ( varholder , holdreflect , templateName , node )
2017-01-21 18:16:27 +00:00
return out
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileIdentswitch ( varholder string , holdreflect reflect . Value , templateName string , node * parse . CommandNode ) ( out string , val reflect . Value ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileIdentswitch" )
2017-06-05 11:57:27 +00:00
}
2017-06-16 10:41:30 +00:00
2017-06-05 11:57:27 +00:00
//var outbuf map[int]string
2017-09-03 04:50:31 +00:00
ArgLoop :
2017-06-05 11:57:27 +00:00
for pos := 0 ; pos < len ( node . Args ) ; pos ++ {
id := node . Args [ pos ]
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "pos:" , pos )
fmt . Println ( "ID:" , id )
2016-12-16 10:37:42 +00:00
}
switch id . String ( ) {
2017-09-03 04:50:31 +00:00
case "not" :
out += "!"
case "or" :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Building or function" )
}
if pos == 0 {
fmt . Println ( "pos:" , pos )
panic ( "or is missing a left operand" )
}
if len ( node . Args ) <= pos {
fmt . Println ( "post pos:" , pos )
fmt . Println ( "len(node.Args):" , len ( node . Args ) )
panic ( "or is missing a right operand" )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
left := c . compileBoolsub ( node . Args [ pos - 1 ] . String ( ) , varholder , templateName , holdreflect )
_ , funcExists := c . funcMap [ node . Args [ pos + 1 ] . String ( ) ]
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
var right string
if ! funcExists {
right = c . compileBoolsub ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
out += left + " || " + right
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Left operand:" , node . Args [ pos - 1 ] )
fmt . Println ( "Right operand:" , node . Args [ pos + 1 ] )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
if ! funcExists {
pos ++
}
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "pos:" , pos )
fmt . Println ( "len(node.Args):" , len ( node . Args ) )
}
case "and" :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Building and function" )
}
if pos == 0 {
fmt . Println ( "pos:" , pos )
panic ( "and is missing a left operand" )
}
if len ( node . Args ) <= pos {
fmt . Println ( "post pos:" , pos )
fmt . Println ( "len(node.Args):" , len ( node . Args ) )
panic ( "and is missing a right operand" )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
left := c . compileBoolsub ( node . Args [ pos - 1 ] . String ( ) , varholder , templateName , holdreflect )
_ , funcExists := c . funcMap [ node . Args [ pos + 1 ] . String ( ) ]
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
var right string
if ! funcExists {
right = c . compileBoolsub ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
out += left + " && " + right
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Left operand:" , node . Args [ pos - 1 ] )
fmt . Println ( "Right operand:" , node . Args [ pos + 1 ] )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
if ! funcExists {
pos ++
}
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "pos:" , pos )
fmt . Println ( "len(node.Args):" , len ( node . Args ) )
}
case "le" :
out += c . compileIfVarsubN ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect ) + " <= " + c . compileIfVarsubN ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "lt" :
out += c . compileIfVarsubN ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect ) + " < " + c . compileIfVarsubN ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "gt" :
out += c . compileIfVarsubN ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect ) + " > " + c . compileIfVarsubN ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "ge" :
out += c . compileIfVarsubN ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect ) + " >= " + c . compileIfVarsubN ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "eq" :
out += c . compileIfVarsubN ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect ) + " == " + c . compileIfVarsubN ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "ne" :
out += c . compileIfVarsubN ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect ) + " != " + c . compileIfVarsubN ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "add" :
param1 , val2 := c . compileIfVarsub ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect )
param2 , val3 := c . compileIfVarsub ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
if val2 . IsValid ( ) {
val = val2
} else if val3 . IsValid ( ) {
val = val3
} else {
numSample := 1
val = reflect . ValueOf ( numSample )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
out += param1 + " + " + param2
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "add" )
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "subtract" :
param1 , val2 := c . compileIfVarsub ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect )
param2 , val3 := c . compileIfVarsub ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
if val2 . IsValid ( ) {
val = val2
} else if val3 . IsValid ( ) {
val = val3
} else {
numSample := 1
val = reflect . ValueOf ( numSample )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
out += param1 + " - " + param2
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "subtract" )
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "divide" :
param1 , val2 := c . compileIfVarsub ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect )
param2 , val3 := c . compileIfVarsub ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
if val2 . IsValid ( ) {
val = val2
} else if val3 . IsValid ( ) {
val = val3
} else {
numSample := 1
val = reflect . ValueOf ( numSample )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
out += param1 + " / " + param2
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "divide" )
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
case "multiply" :
param1 , val2 := c . compileIfVarsub ( node . Args [ pos + 1 ] . String ( ) , varholder , templateName , holdreflect )
param2 , val3 := c . compileIfVarsub ( node . Args [ pos + 2 ] . String ( ) , varholder , templateName , holdreflect )
if val2 . IsValid ( ) {
val = val2
} else if val3 . IsValid ( ) {
val = val3
} else {
numSample := 1
val = reflect . ValueOf ( numSample )
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
out += param1 + " * " + param2
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "multiply" )
fmt . Println ( "node.Args[pos + 1]" , node . Args [ pos + 1 ] )
fmt . Println ( "node.Args[pos + 2]" , node . Args [ pos + 2 ] )
}
break ArgLoop
default :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Variable!" )
}
if len ( node . Args ) > ( pos + 1 ) {
nextNode := node . Args [ pos + 1 ] . String ( )
if nextNode == "or" || nextNode == "and" {
continue
2017-06-05 11:57:27 +00:00
}
2017-09-03 04:50:31 +00:00
}
out += c . compileIfVarsubN ( id . String ( ) , varholder , templateName , holdreflect )
2016-12-16 10:37:42 +00:00
}
}
2017-06-16 10:41:30 +00:00
2017-06-05 11:57:27 +00:00
//for _, outval := range outbuf {
// out += outval
//}
2017-01-21 18:16:27 +00:00
return out , val
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileReflectswitch ( varholder string , holdreflect reflect . Value , templateName string , node * parse . CommandNode ) ( out string , outVal reflect . Value ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileReflectswitch" )
2017-06-05 11:57:27 +00:00
}
2016-12-16 10:37:42 +00:00
firstWord := node . Args [ 0 ]
switch n := firstWord . ( type ) {
2017-09-03 04:50:31 +00:00
case * parse . FieldNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Field Node:" , n . Ident )
for _ , id := range n . Ident {
fmt . Println ( "Field Bit:" , id )
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
return c . compileIfVarsub ( n . String ( ) , varholder , templateName , holdreflect )
case * parse . ChainNode :
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "Chain Node:" , n . Node )
fmt . Println ( "node.Args" , 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")
2016-12-16 10:37:42 +00:00
}
return "" , outVal
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileIfVarsubN ( varname string , varholder string , templateName string , cur reflect . Value ) ( out string ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileIfVarsubN" )
2017-06-05 11:57:27 +00:00
}
2017-09-03 04:50:31 +00:00
out , _ = c . compileIfVarsub ( varname , varholder , templateName , cur )
2016-12-16 10:37:42 +00:00
return out
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileIfVarsub ( varname string , varholder string , templateName string , cur reflect . Value ) ( out string , val reflect . Value ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileIfVarsub" )
2017-06-05 11:57:27 +00:00
}
2016-12-16 10:37:42 +00:00
if varname [ 0 ] != '.' && varname [ 0 ] != '$' {
return varname , cur
}
2017-06-16 10:41:30 +00:00
2017-09-03 04:50:31 +00:00
bits := strings . Split ( varname , "." )
2016-12-16 10:37:42 +00:00
if varname [ 0 ] == '$' {
var res VarItemReflect
if varname [ 1 ] == '.' {
2017-09-03 04:50:31 +00:00
res = c . localVars [ templateName ] [ "." ]
2016-12-16 10:37:42 +00:00
} else {
2017-09-03 04:50:31 +00:00
res = c . localVars [ templateName ] [ strings . TrimPrefix ( bits [ 0 ] , "$" ) ]
2016-12-16 10:37:42 +00:00
}
out += res . Destination
cur = res . Value
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
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
}
}
2017-09-03 04:50:31 +00:00
bits [ 0 ] = strings . TrimPrefix ( bits [ 0 ] , "$" )
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "Cur Kind:" , cur . Kind ( ) )
fmt . Println ( "Cur Type:" , cur . Type ( ) . Name ( ) )
2016-12-16 10:37:42 +00:00
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
for _ , bit := range bits {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "Variable Field:" , bit )
2016-12-16 10:37:42 +00:00
}
if bit == "" {
continue
}
2017-06-16 10:41:30 +00:00
2017-09-10 16:57:22 +00:00
// TODO: Fix this up so that it works for regular pointers and not just struct pointers. Ditto for the other cur.Kind() == reflect.Ptr we have in this file
2017-08-06 15:22:18 +00:00
if cur . Kind ( ) == reflect . Ptr {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-06 15:22:18 +00:00
fmt . Println ( "Looping over pointer" )
}
for cur . Kind ( ) == reflect . Ptr {
cur = cur . Elem ( )
}
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "Data Kind:" , cur . Kind ( ) . String ( ) )
fmt . Println ( "Field Bit:" , bit )
2017-08-06 15:22:18 +00:00
}
}
2016-12-16 10:37:42 +00:00
cur = cur . FieldByName ( bit )
if cur . Kind ( ) == reflect . Interface {
cur = cur . Elem ( )
out += "." + bit + ".(" + cur . Type ( ) . Name ( ) + ")"
} else {
out += "." + bit
}
2017-06-16 10:41:30 +00:00
2017-06-19 08:06:54 +00:00
if ! cur . IsValid ( ) {
panic ( out + "^\n" + "Invalid value. Maybe, it doesn't exist?" )
}
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "Data Kind:" , cur . Kind ( ) )
fmt . Println ( "Data Type:" , cur . Type ( ) . Name ( ) )
2016-12-16 10:37:42 +00:00
}
}
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "Out Value:" , out )
fmt . Println ( "Out Kind:" , cur . Kind ( ) )
fmt . Println ( "Out Type:" , cur . Type ( ) . Name ( ) )
2017-01-21 18:16:27 +00:00
}
2017-06-16 10:41:30 +00:00
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 )
}
}
2017-06-16 10:41:30 +00:00
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "Out Value:" , out )
fmt . Println ( "Out Kind:" , cur . Kind ( ) )
fmt . Println ( "Out Type:" , cur . Type ( ) . Name ( ) )
2017-01-21 18:16:27 +00:00
}
2017-06-16 10:41:30 +00:00
2016-12-17 03:39:53 +00:00
_ , ok := c . stats [ out ]
if ok {
c . stats [ out ] ++
} else {
c . stats [ out ] = 1
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
return out , cur
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileBoolsub ( varname string , varholder string , templateName string , val reflect . Value ) string {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileBoolsub" )
2017-06-05 11:57:27 +00:00
}
2017-09-03 04:50:31 +00:00
out , val := c . compileIfVarsub ( varname , varholder , templateName , val )
2016-12-16 10:37:42 +00:00
switch val . Kind ( ) {
2017-09-03 04:50:31 +00:00
case reflect . Int :
out += " > 0"
case reflect . Bool : // Do nothing
case reflect . String :
out += " != \"\""
case reflect . Int64 :
out += " > 0"
default :
fmt . Println ( "Variable Name:" , varname )
fmt . Println ( "Variable Holder:" , varholder )
fmt . Println ( "Variable Kind:" , val . Kind ( ) )
panic ( "I don't know what this variable's type is o.o\n" )
2016-12-16 10:37:42 +00:00
}
return out
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileVarsub ( varname string , val reflect . Value ) string {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileVarsub" )
2017-06-05 11:57:27 +00:00
}
2016-12-16 10:37:42 +00:00
for _ , varItem := range c . varList {
if strings . HasPrefix ( varname , varItem . Destination ) {
varname = strings . Replace ( varname , varItem . Destination , varItem . Name , 1 )
}
}
2017-06-16 10:41:30 +00:00
2016-12-17 03:39:53 +00:00
_ , ok := c . stats [ varname ]
if ok {
c . stats [ varname ] ++
} else {
c . stats [ varname ] = 1
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
if val . Kind ( ) == reflect . Interface {
val = val . Elem ( )
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
switch val . Kind ( ) {
2017-09-03 04:50:31 +00:00
case reflect . Int :
c . importMap [ "strconv" ] = "strconv"
return "w.Write([]byte(strconv.Itoa(" + varname + ")))\n"
case reflect . Bool :
return "if " + varname + " {\nw.Write([]byte(\"true\"))} else {\nw.Write([]byte(\"false\"))\n}\n"
case reflect . String :
if val . Type ( ) . Name ( ) != "string" && ! strings . HasPrefix ( varname , "string(" ) {
return "w.Write([]byte(string(" + varname + ")))\n"
}
return "w.Write([]byte(" + varname + "))\n"
case reflect . Int64 :
c . importMap [ "strconv" ] = "strconv"
return "w.Write([]byte(strconv.FormatInt(" + varname + ", 10)))"
default :
if ! val . IsValid ( ) {
panic ( varname + "^\n" + "Invalid value. Maybe, it doesn't exist?" )
}
fmt . Println ( "Unknown Variable Name:" , varname )
fmt . Println ( "Unknown Kind:" , val . Kind ( ) )
fmt . Println ( "Unknown Type:" , val . Type ( ) . Name ( ) )
panic ( "// I don't know what this variable's type is o.o\n" )
2016-12-16 10:37:42 +00:00
}
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileSubtemplate ( pvarholder string , pholdreflect reflect . Value , node * parse . TemplateNode ) ( out string ) {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-09-03 04:50:31 +00:00
fmt . Println ( "in compileSubtemplate" )
2017-08-13 11:22:34 +00:00
fmt . Println ( "Template Node:" , node . Name )
2016-12-16 10:37:42 +00:00
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
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 ) {
2017-09-03 04:50:31 +00:00
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 . compileCommand ( cmd )
2016-12-16 10:37:42 +00:00
}
}
}
2017-06-16 10:41:30 +00:00
2017-09-10 16:57:22 +00:00
// TODO: Cascade errors back up the tree to the caller?
2016-12-16 10:37:42 +00:00
res , err := ioutil . ReadFile ( c . dir + node . Name )
if err != nil {
log . Fatal ( err )
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
content := string ( res )
2017-07-17 10:23:42 +00:00
if config . MinifyTemplates {
2017-02-11 14:51:16 +00:00
content = minify ( content )
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
tree := parse . New ( node . Name , c . funcMap )
2017-09-03 04:50:31 +00:00
var treeSet = make ( map [ string ] * parse . Tree )
tree , err = tree . Parse ( content , "{{" , "}}" , treeSet , c . funcMap )
2016-12-16 10:37:42 +00:00
if err != nil {
log . Fatal ( err )
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
c . tlist [ fname ] = tree
subtree := c . tlist [ fname ]
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "subtree.Root" , subtree . Root )
2016-12-16 10:37:42 +00:00
}
2017-06-16 10:41:30 +00:00
2016-12-16 10:37:42 +00:00
c . localVars [ fname ] = make ( map [ string ] VarItemReflect )
2017-09-03 04:50:31 +00:00
c . localVars [ fname ] [ "." ] = VarItemReflect { "." , varholder , holdreflect }
2017-01-17 07:55:46 +00:00
c . FragmentCursor [ fname ] = 0
2017-06-16 10:41:30 +00:00
2016-12-18 12:56:06 +00:00
treeLength := len ( subtree . Root . Nodes )
for index , node := range subtree . Root . Nodes {
2017-09-23 21:28:50 +00:00
if dev . TemplateDebug {
2017-08-13 11:22:34 +00:00
fmt . Println ( "Node:" , node . String ( ) )
2016-12-16 10:37:42 +00:00
}
2017-06-16 10:41:30 +00:00
2016-12-18 12:56:06 +00:00
c . previousNode = c . currentNode
c . currentNode = node . Type ( )
if treeLength != ( index + 1 ) {
2017-09-03 04:50:31 +00:00
c . nextNode = subtree . Root . Nodes [ index + 1 ] . Type ( )
2016-12-18 12:56:06 +00:00
}
2017-09-03 04:50:31 +00:00
out += c . compileSwitch ( varholder , holdreflect , fname , node )
2016-12-16 10:37:42 +00:00
}
2017-06-16 10:41:30 +00:00
return out
2016-12-16 10:37:42 +00:00
}
2017-09-03 04:50:31 +00:00
func ( c * CTemplateSet ) compileCommand ( * parse . CommandNode ) ( out string ) {
2017-02-15 10:49:30 +00:00
panic ( "Uh oh! Something went wrong!" )
2017-02-11 14:51:16 +00:00
}
2017-09-10 16:57:22 +00:00
// TODO: Write unit tests for this
2017-02-11 14:51:16 +00:00
func minify ( data string ) string {
2017-09-03 04:50:31 +00:00
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 )
2017-02-11 14:51:16 +00:00
return data
}
2017-07-29 10:36:39 +00:00
2017-09-10 16:57:22 +00:00
// TODO: Strip comments
// TODO: Handle CSS nested in <style> tags?
// TODO: Write unit tests for this
2017-09-03 04:50:31 +00:00
func minifyHTML ( data string ) string {
2017-07-29 10:36:39 +00:00
return minify ( data )
}
2017-09-10 16:57:22 +00:00
// TODO: Have static files use this
// TODO: Strip comments
// TODO: Convert the rgb()s to hex codes?
// TODO: Write unit tests for this
2017-09-03 04:50:31 +00:00
func minifyCSS ( data string ) string {
2017-07-29 10:36:39 +00:00
return minify ( data )
}
2017-09-10 16:57:22 +00:00
// TODO: Convert this to three character hex strings whenever possible?
// TODO: Write unit tests for this
2017-09-03 04:50:31 +00:00
// nolint
func rgbToHexstr ( red int , green int , blue int ) string {
2017-07-29 10:36:39 +00:00
return strconv . FormatInt ( int64 ( red ) , 16 ) + strconv . FormatInt ( int64 ( green ) , 16 ) + strconv . FormatInt ( int64 ( blue ) , 16 )
}
/ *
2017-09-10 16:57:22 +00:00
// TODO: Write unit tests for this
2017-09-03 04:50:31 +00:00
func hexstrToRgb ( hexstr string ) ( red int , blue int , green int , err error ) {
2017-07-29 10:36:39 +00:00
// Strip the # at the start
if hexstr [ 0 ] == '#' {
hexstr = strings . TrimPrefix ( hexstr , "#" )
}
if len ( hexstr ) != 3 && len ( hexstr ) != 6 {
return 0 , 0 , 0 , errors . New ( "Hex colour codes may only be three or six characters long" )
}
if len ( hexstr ) == 3 {
hexstr = hexstr [ 0 ] + hexstr [ 0 ] + hexstr [ 1 ] + hexstr [ 1 ] + hexstr [ 2 ] + hexstr [ 2 ]
}
} * /