func stringFormat(context *parser.FunctionCallContext) error { values, err := parser.ValidateArguments(context, "string-format", parser.VALUE_STRING) if err != nil { return err } format := values[0].S count := strings.Count(format, "{}") if count > context.Block.Stack.Len() { return util.NewArgumentCountError("string-format", count, context.Block.Stack.Len(), context.Token.Line, context.Token.Column, context.Token.File) } var items []*parser.Value for i := 0; i < count; i++ { items = append(items, context.Block.Stack.Pop().(*parser.Value)) } for i := count - 1; i >= 0; i-- { format = strings.Replace(format, "{}", items[i].String(), 1) } context.Block.Stack.Push(parser.NewValueFromString(format)) return nil }
func ValidateArguments(context *FunctionCallContext, name string, types ...ValueType) ([]*Value, error) { if context.Block.Stack.Len() >= len(types) { var values []*Value for _, t := range types { value := context.Block.Stack.Pop().(*Value) if value.Type != t && t != VALUE_ANY { return nil, util.NewArgumentTypeError(name, t, value.Type, context.Token.Line, context.Token.Column, context.Token.File) } values = append(values, value) } return values, nil } return nil, util.NewArgumentCountError(name, len(types), context.Block.Stack.Len(), context.Token.Line, context.Token.Column, context.Token.File) }
func (f *Function) Exec(block *Block, token *lexer.Token) error { switch f.Type { case FUNCTION_LAMBDA: lambda := f.L err := lambda.Exec() lambda.Stack.PopAllToOtherStack(block.Stack) return err case FUNCTION_BUILTIN: return f.B(&FunctionCallContext{Block: block, Token: token}) case FUNCTION_DECLARED: if block.Stack.Len() < len(f.Args) { return util.NewArgumentCountError(f.Name, len(f.Args), block.Stack.Len(), token.Line, token.Column, token.File) } for i := len(f.Args) - 1; i >= 0; i-- { f.D.Scope.SetSymbolLocally(f.Args[i], NewSymbol(block.Stack.Pop().(*Value), false, false)) } err := f.D.Exec() if f.Name[len(f.Name)-1] == '?' { if err != nil { return err } if f.D.Stack.Len() != 1 { return util.NewReturnCountError(f.Name, 1, f.D.Stack.Len(), token.Line, token.Column, token.File) } top := f.D.Stack.Peek(0).(*Value) if top.Type != VALUE_BOOL { return util.NewReturnTypeError(f.Name, VALUE_BOOL, top.Type, token.Line, token.Column, token.File) } } f.D.Stack.PopAllToOtherStack(block.Stack) return err default: panic("cannot execute function") } }