OILS / builtin / func_reflect.py View on Github | oilshell.org

140 lines, 79 significant
1#!/usr/bin/env python2
2"""
3func_reflect.py - Functions for reflecting on Oils code - OSH or YSH.
4"""
5from __future__ import print_function
6
7from _devbuild.gen.runtime_asdl import (scope_e)
8from _devbuild.gen.syntax_asdl import source
9from _devbuild.gen.value_asdl import (value, value_t)
10
11from core import alloc
12from core import error
13from core import main_loop
14from core import state
15from core import vm
16from frontend import location
17from frontend import reader
18from frontend import typed_args
19from mycpp.mylib import log
20from ysh import expr_eval
21
22from typing import TYPE_CHECKING
23if TYPE_CHECKING:
24 from frontend import parse_lib
25 from display import ui
26
27_ = log
28
29
30class Shvar_get(vm._Callable):
31 """Look up with dynamic scope."""
32
33 def __init__(self, mem):
34 # type: (state.Mem) -> None
35 vm._Callable.__init__(self)
36 self.mem = mem
37
38 def Call(self, rd):
39 # type: (typed_args.Reader) -> value_t
40 name = rd.PosStr()
41 rd.Done()
42 return state.DynamicGetVar(self.mem, name, scope_e.Dynamic)
43
44
45class GetVar(vm._Callable):
46 """Look up a variable, with normal scoping rules."""
47
48 def __init__(self, mem):
49 # type: (state.Mem) -> None
50 vm._Callable.__init__(self)
51 self.mem = mem
52
53 def Call(self, rd):
54 # type: (typed_args.Reader) -> value_t
55 name = rd.PosStr()
56 rd.Done()
57 return state.DynamicGetVar(self.mem, name, scope_e.LocalOrGlobal)
58
59
60class SetVar(vm._Callable):
61 """Set a variable in the local scope.
62
63 We could have a separae setGlobal() too.
64 """
65
66 def __init__(self, mem):
67 # type: (state.Mem) -> None
68 vm._Callable.__init__(self)
69 self.mem = mem
70
71 def Call(self, rd):
72 # type: (typed_args.Reader) -> value_t
73 var_name = rd.PosStr()
74 val = rd.PosValue()
75 rd.Done()
76 self.mem.SetNamed(location.LName(var_name), val, scope_e.LocalOnly)
77 return value.Null
78
79
80class ParseCommand(vm._Callable):
81
82 def __init__(self, parse_ctx, errfmt):
83 # type: (parse_lib.ParseContext, ui.ErrorFormatter) -> None
84 self.parse_ctx = parse_ctx
85 self.errfmt = errfmt
86
87 def Call(self, rd):
88 # type: (typed_args.Reader) -> value_t
89 code_str = rd.PosStr()
90 rd.Done()
91
92 line_reader = reader.StringLineReader(code_str, self.parse_ctx.arena)
93 c_parser = self.parse_ctx.MakeOshParser(line_reader)
94
95 # TODO: it would be nice to point to the location of the expression
96 # argument
97 src = source.Dynamic('parseCommand()', rd.LeftParenToken())
98 with alloc.ctx_SourceCode(self.parse_ctx.arena, src):
99 try:
100 cmd = main_loop.ParseWholeFile(c_parser)
101 except error.Parse as e:
102 # This prints the location
103 self.errfmt.PrettyPrintError(e)
104
105 # TODO: add inner location info to this structured error
106 raise error.Structured(3, "Syntax error in parseCommand()",
107 rd.LeftParenToken())
108
109 return value.Command(cmd)
110
111
112class ParseExpr(vm._Callable):
113
114 def __init__(self, parse_ctx, errfmt):
115 # type: (parse_lib.ParseContext, ui.ErrorFormatter) -> None
116 self.parse_ctx = parse_ctx
117 self.errfmt = errfmt
118
119 def Call(self, rd):
120 # type: (typed_args.Reader) -> value_t
121 code_str = rd.PosStr()
122 rd.Done()
123
124 return value.Null
125
126
127class EvalExpr(vm._Callable):
128
129 def __init__(self, expr_ev):
130 # type: (expr_eval.ExprEvaluator) -> None
131 self.expr_ev = expr_ev
132
133 def Call(self, rd):
134 # type: (typed_args.Reader) -> value_t
135 lazy = rd.PosExpr()
136 rd.Done()
137
138 result = self.expr_ev.EvalExpr(lazy, rd.LeftParenToken())
139
140 return result