...

Source file src/github.com/noirbizarre/gonja/builtins/statements/import.go

Documentation: github.com/noirbizarre/gonja/builtins/statements

     1  package statements
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/pkg/errors"
     7  
     8  	"github.com/noirbizarre/gonja/exec"
     9  	"github.com/noirbizarre/gonja/nodes"
    10  	"github.com/noirbizarre/gonja/parser"
    11  	"github.com/noirbizarre/gonja/tokens"
    12  )
    13  
    14  type ImportStmt struct {
    15  	Location     *tokens.Token
    16  	Filename     string
    17  	FilenameExpr nodes.Expression
    18  	As           string
    19  	WithContext  bool
    20  	Template     *nodes.Template
    21  }
    22  
    23  func (stmt *ImportStmt) Position() *tokens.Token { return stmt.Location }
    24  func (stmt *ImportStmt) String() string {
    25  	t := stmt.Position()
    26  	return fmt.Sprintf("ImportStmt(Line=%d Col=%d)", t.Line, t.Col)
    27  }
    28  func (stmt *ImportStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
    29  	var imported map[string]*nodes.Macro
    30  	macros := map[string]exec.Macro{}
    31  
    32  	if stmt.FilenameExpr != nil {
    33  		filenameValue := r.Eval(stmt.FilenameExpr)
    34  		if filenameValue.IsError() {
    35  			return errors.Wrap(filenameValue, `Unable to evaluate filename`)
    36  		}
    37  
    38  		filename := filenameValue.String()
    39  		tpl, err := r.Loader.GetTemplate(filename)
    40  		if err != nil {
    41  			return errors.Wrapf(err, `Unable to load template '%s'`, filename)
    42  		}
    43  		imported = tpl.Root.Macros
    44  
    45  	} else {
    46  		imported = stmt.Template.Macros
    47  	}
    48  
    49  	for name, macro := range imported {
    50  		fn, err := exec.MacroNodeToFunc(macro, r)
    51  		if err != nil {
    52  			return errors.Wrapf(err, `Unable to import macro '%s'`, name)
    53  		}
    54  		macros[name] = fn
    55  	}
    56  
    57  	r.Ctx.Set(stmt.As, macros)
    58  	return nil
    59  }
    60  
    61  type FromImportStmt struct {
    62  	Location     *tokens.Token
    63  	Filename     string
    64  	FilenameExpr nodes.Expression
    65  	WithContext  bool
    66  	Template     *nodes.Template
    67  	As           map[string]string
    68  	Macros       map[string]*nodes.Macro // alias/name -> macro instance
    69  }
    70  
    71  func (stmt *FromImportStmt) Position() *tokens.Token { return stmt.Location }
    72  func (stmt *FromImportStmt) String() string {
    73  	t := stmt.Position()
    74  	return fmt.Sprintf("FromImportStmt(Line=%d Col=%d)", t.Line, t.Col)
    75  }
    76  func (stmt *FromImportStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
    77  	var imported map[string]*nodes.Macro
    78  
    79  	if stmt.FilenameExpr != nil {
    80  		filenameValue := r.Eval(stmt.FilenameExpr)
    81  		if filenameValue.IsError() {
    82  			return errors.Wrap(filenameValue, `Unable to evaluate filename`)
    83  		}
    84  
    85  		filename := filenameValue.String()
    86  		tpl, err := r.Loader.GetTemplate(filename)
    87  		if err != nil {
    88  			return errors.Wrapf(err, `Unable to load template '%s'`, filename)
    89  		}
    90  		imported = tpl.Root.Macros
    91  
    92  	} else {
    93  		imported = stmt.Template.Macros
    94  	}
    95  
    96  	for alias, name := range stmt.As {
    97  		node := imported[name]
    98  		fn, err := exec.MacroNodeToFunc(node, r)
    99  		if err != nil {
   100  			return errors.Wrapf(err, `Unable to import macro '%s'`, name)
   101  		}
   102  		r.Ctx.Set(alias, fn)
   103  	}
   104  	return nil
   105  }
   106  
   107  func importParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
   108  	stmt := &ImportStmt{
   109  		Location: p.Current(),
   110  		// Macros:   map[string]*nodes.Macro{},
   111  	}
   112  
   113  	if args.End() {
   114  		return nil, args.Error("You must at least specify one macro to import.", nil)
   115  	}
   116  
   117  	if tok := args.Match(tokens.String); tok != nil {
   118  		stmt.Filename = tok.Val
   119  	} else {
   120  		expr, err := args.ParseExpression()
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  		stmt.FilenameExpr = expr
   125  	}
   126  	if args.MatchName("as") == nil {
   127  		return nil, args.Error(`Expected "as" keyword`, args.Current())
   128  	}
   129  
   130  	alias := args.Match(tokens.Name)
   131  	if alias == nil {
   132  		return nil, args.Error("Expected macro alias name (identifier)", args.Current())
   133  	}
   134  	stmt.As = alias.Val
   135  
   136  	if tok := args.MatchName("with", "without"); tok != nil {
   137  		if args.MatchName("context") != nil {
   138  			stmt.WithContext = tok.Val == "with"
   139  		} else {
   140  			args.Stream.Backup()
   141  		}
   142  	}
   143  
   144  	// Preload static template
   145  	if stmt.Filename != "" {
   146  		tpl, err := p.TemplateParser(stmt.Filename)
   147  		if err != nil {
   148  			return nil, errors.Wrapf(err, `Unable to parse imported template '%s'`, stmt.Filename)
   149  		} else {
   150  			stmt.Template = tpl
   151  		}
   152  	}
   153  
   154  	return stmt, nil
   155  }
   156  
   157  func fromParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
   158  	stmt := &FromImportStmt{
   159  		Location: p.Current(),
   160  		As:       map[string]string{},
   161  		// Macros:   map[string]*nodes.Macro{},
   162  	}
   163  
   164  	if args.End() {
   165  		return nil, args.Error("You must at least specify one macro to import.", nil)
   166  	}
   167  
   168  	if tok := args.Match(tokens.String); tok != nil {
   169  		stmt.Filename = tok.Val
   170  	} else {
   171  		filename, err := args.ParseExpression()
   172  		if err != nil {
   173  			return nil, err
   174  		}
   175  		stmt.FilenameExpr = filename
   176  	}
   177  
   178  	if args.MatchName("import") == nil {
   179  		return nil, args.Error("Expected import keyword", args.Current())
   180  	}
   181  
   182  	for !args.End() {
   183  		name := args.Match(tokens.Name)
   184  		if name == nil {
   185  			return nil, args.Error("Expected macro name (identifier).", args.Current())
   186  		}
   187  
   188  		// asName := macroNameToken.Val
   189  		if args.MatchName("as") != nil {
   190  			alias := args.Match(tokens.Name)
   191  			if alias == nil {
   192  				return nil, args.Error("Expected macro alias name (identifier).", nil)
   193  			}
   194  			// asName = aliasToken.Val
   195  			stmt.As[alias.Val] = name.Val
   196  		} else {
   197  			stmt.As[name.Val] = name.Val
   198  		}
   199  
   200  		// macroInstance, has := tpl.exportedMacros[macroNameToken.Val]
   201  		// if !has {
   202  		// 	return nil, args.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macroNameToken.Val,
   203  		// 		stmt.filename), macroNameToken)
   204  		// }
   205  
   206  		// stmt.macros[asName] = macroInstance
   207  		if tok := args.MatchName("with", "without"); tok != nil {
   208  			if args.MatchName("context") != nil {
   209  				stmt.WithContext = tok.Val == "with"
   210  				break
   211  			} else {
   212  				args.Stream.Backup()
   213  			}
   214  		}
   215  
   216  		if args.End() {
   217  			break
   218  		}
   219  
   220  		if args.Match(tokens.Comma) == nil {
   221  			return nil, args.Error("Expected ','.", nil)
   222  		}
   223  	}
   224  
   225  	// Preload static template
   226  	if stmt.Filename != "" {
   227  		tpl, err := p.TemplateParser(stmt.Filename)
   228  		if err != nil {
   229  			return nil, errors.Wrapf(err, `Unable to parse imported template '%s'`, stmt.Filename)
   230  		} else {
   231  			stmt.Template = tpl
   232  		}
   233  	}
   234  
   235  	return stmt, nil
   236  }
   237  
   238  func init() {
   239  	All.Register("import", importParser)
   240  	All.Register("from", fromParser)
   241  }
   242  

View as plain text