Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions repl/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ type parseCmd struct {
}

type evalCmd struct {
expr string
parseOnly bool
expr string
}

// Cmder interface provides normalized command name from a repl command.
Expand Down Expand Up @@ -308,7 +309,18 @@ func (c *commandParseListener) EnterParse(ctx *parser.ParseContext) {
}

func (c *commandParseListener) EnterExprCmd(ctx *parser.ExprCmdContext) {
c.cmd = &evalCmd{}
cmd := &evalCmd{}
for _, f := range ctx.GetFlags() {
ft := strings.TrimPrefix(strings.TrimPrefix(f.GetText(), "--"), "-")
switch ft {
case "parse-only":
cmd.parseOnly = true
default:
c.reportIssue(fmt.Errorf("unknown or unsupported flag: %q", ft))
return
}
}
c.cmd = cmd
}

func (c *commandParseListener) ExitFnDecl(ctx *parser.FnDeclContext) {
Expand Down
29 changes: 27 additions & 2 deletions repl/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,10 @@ func TestParse(t *testing.T) {
%exit`),
},
{
commandLine: `%arbitrary --flag -FLAG 'string literal\n'`,
commandLine: `%arbitrary --flag --another-flag 'string literal\n'`,
wantCmd: &simpleCmd{cmd: "arbitrary",
args: []string{
"--flag", "--flag", "string literal\\n",
"--flag", "--another-flag", "string literal\\n",
},
},
},
Expand Down Expand Up @@ -284,6 +284,13 @@ func TestParse(t *testing.T) {
src: "",
},
},
{
commandLine: `%eval --parse-only -- foo`,
wantCmd: &evalCmd{
parseOnly: true,
expr: `foo`,
},
},
}

for _, tc := range testCases {
Expand Down Expand Up @@ -344,6 +351,24 @@ func TestParseErrors(t *testing.T) {
// not an identifier
commandLine: "%delete 123",
},
{
commandLine: "%eval --badflag foo",
},
{
commandLine: "%eval --bad-flag foo",
},
{
commandLine: "%eval -badflag foo",
},
{
commandLine: "%eval -bad-flag foo",
},
{
commandLine: "%eval --parse-only foo",
},
{
commandLine: "%eval -parse-only foo",
},
}
for _, tc := range testCases {
_, err := Parse(tc.commandLine)
Expand Down
39 changes: 37 additions & 2 deletions repl/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1302,16 +1302,28 @@ func (e *Evaluator) Process(cmd Cmder) (string, bool, error) {
}
return prototext.Format(pAST), false, nil
case *evalCmd:
val, resultT, err := e.Evaluate(cmd.expr)
var (
val ref.Val
resultT *exprpb.Type
err error
)
if cmd.parseOnly {
val, resultT, err = e.EvaluateParseOnly(cmd.expr)
} else {
val, resultT, err = e.Evaluate(cmd.expr)
}
if err != nil {
return "", false, fmt.Errorf("expr failed:\n%v", err)
}
if val != nil {
t := UnparseType(resultT)
unknown, ok := val.Value().(*types.Unknown)
if ok {
return fmt.Sprintf("Unknown %v", unknown), false, nil
}
if cmd.parseOnly {
return fmt.Sprintf("%s", types.Format(val)), false, nil
}
t := UnparseType(resultT)
return fmt.Sprintf("%s : %s", types.Format(val), t), false, nil
}
case *letVarCmd:
Expand Down Expand Up @@ -1394,6 +1406,29 @@ func (e *Evaluator) Evaluate(expr string) (ref.Val, *exprpb.Type, error) {
return val, ast.ResultType(), err
}

// EvaluateParseOnly evalutes the CEL expression using the current REPL context without type checking.
func (e *Evaluator) EvaluateParseOnly(expr string) (ref.Val, *exprpb.Type, error) {
env, act, err := e.applyContext()
if err != nil {
return nil, nil, err
}

ast, iss := env.Parse(expr)
if iss.Err() != nil {
return nil, nil, iss.Err()
}

p, err := env.Program(ast, e.ctx.programOptions()...)
if err != nil {
return nil, nil, err
}

act, _ = env.PartialVars(act)
val, _, err := p.Eval(act)
// expression can be well-formed and result in an error
return val, ast.ResultType(), err
}

// Compile compiles the input expression using the current REPL context.
func (e *Evaluator) Compile(expr string) (*cel.Ast, error) {
env, _, err := e.applyContext()
Expand Down
4 changes: 2 additions & 2 deletions repl/parser/Commands.g4
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ compile: '%compile' e=expr;

parse: '%parse' e=expr;

exprCmd: '%eval'? e=expr;
exprCmd: ('%eval' (flags+=FLAG (flags+=FLAG)* '--')?)? e=expr;

qualId: leadingDot='.'? rid=IDENTIFIER ('.' qualifiers+=IDENTIFIER)*;

Expand All @@ -69,6 +69,6 @@ typeParamList:

// lexer rules:
COMMAND: '%' IDENTIFIER;
FLAG: '-'? '-' IDENTIFIER;
FLAG: '-' ('-' IDENTIFIER)+;
ARROW: '->';
EQUAL_ASSIGN: '=';
4 changes: 3 additions & 1 deletion repl/parser/Commands.interp

Large diffs are not rendered by default.

144 changes: 73 additions & 71 deletions repl/parser/Commands.tokens
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,48 @@ T__4=5
T__5=6
T__6=7
T__7=8
COMMAND=9
FLAG=10
ARROW=11
EQUAL_ASSIGN=12
EQUALS=13
NOT_EQUALS=14
IN=15
LESS=16
LESS_EQUALS=17
GREATER_EQUALS=18
GREATER=19
LOGICAL_AND=20
LOGICAL_OR=21
LBRACKET=22
RPRACKET=23
LBRACE=24
RBRACE=25
LPAREN=26
RPAREN=27
DOT=28
COMMA=29
MINUS=30
EXCLAM=31
QUESTIONMARK=32
COLON=33
PLUS=34
STAR=35
SLASH=36
PERCENT=37
CEL_TRUE=38
CEL_FALSE=39
NUL=40
WHITESPACE=41
COMMENT=42
NUM_FLOAT=43
NUM_INT=44
NUM_UINT=45
STRING=46
BYTES=47
IDENTIFIER=48
ESC_IDENTIFIER=49
T__8=9
COMMAND=10
FLAG=11
ARROW=12
EQUAL_ASSIGN=13
EQUALS=14
NOT_EQUALS=15
IN=16
LESS=17
LESS_EQUALS=18
GREATER_EQUALS=19
GREATER=20
LOGICAL_AND=21
LOGICAL_OR=22
LBRACKET=23
RPRACKET=24
LBRACE=25
RBRACE=26
LPAREN=27
RPAREN=28
DOT=29
COMMA=30
MINUS=31
EXCLAM=32
QUESTIONMARK=33
COLON=34
PLUS=35
STAR=36
SLASH=37
PERCENT=38
CEL_TRUE=39
CEL_FALSE=40
NUL=41
WHITESPACE=42
COMMENT=43
NUM_FLOAT=44
NUM_INT=45
NUM_UINT=46
STRING=47
BYTES=48
IDENTIFIER=49
ESC_IDENTIFIER=50
'%help'=1
'%?'=2
'%let'=3
Expand All @@ -55,33 +56,34 @@ ESC_IDENTIFIER=49
'%compile'=6
'%parse'=7
'%eval'=8
'->'=11
'='=12
'=='=13
'!='=14
'in'=15
'<'=16
'<='=17
'>='=18
'>'=19
'&&'=20
'||'=21
'['=22
']'=23
'{'=24
'}'=25
'('=26
')'=27
'.'=28
','=29
'-'=30
'!'=31
'?'=32
':'=33
'+'=34
'*'=35
'/'=36
'%'=37
'true'=38
'false'=39
'null'=40
'--'=9
'->'=12
'='=13
'=='=14
'!='=15
'in'=16
'<'=17
'<='=18
'>='=19
'>'=20
'&&'=21
'||'=22
'['=23
']'=24
'{'=25
'}'=26
'('=27
')'=28
'.'=29
','=30
'-'=31
'!'=32
'?'=33
':'=34
'+'=35
'*'=36
'/'=37
'%'=38
'true'=39
'false'=40
'null'=41
5 changes: 4 additions & 1 deletion repl/parser/CommandsLexer.interp

Large diffs are not rendered by default.

Loading