Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Replace ctx with a pure YSH definition #2087

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
104 changes: 2 additions & 102 deletions builtin/pure_ysh.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from __future__ import print_function

from _devbuild.gen.runtime_asdl import cmd_value
from _devbuild.gen.syntax_asdl import command_t, loc, loc_t
from _devbuild.gen.syntax_asdl import loc
from _devbuild.gen.value_asdl import value, value_e, value_t
from core import error
from core import state
Expand All @@ -14,7 +14,7 @@
from mycpp import mylib
from mycpp.mylib import tagswitch, NewDict

from typing import TYPE_CHECKING, cast, Any, Dict, List
from typing import TYPE_CHECKING, cast, Dict, List

if TYPE_CHECKING:
from display import ui
Expand Down Expand Up @@ -63,106 +63,6 @@ def Run(self, cmd_val):
return 0


class ctx_Context(object):
"""For ctx push (context) { ... }"""

def __init__(self, mem, context):
# type: (state.Mem, Dict[str, value_t]) -> None
self.mem = mem
self.mem.PushContextStack(context)

def __enter__(self):
# type: () -> None
pass

def __exit__(self, type, value, traceback):
# type: (Any, Any, Any) -> None
self.mem.PopContextStack()


class Ctx(vm._Builtin):

def __init__(self, mem, cmd_ev):
# type: (state.Mem, CommandEvaluator) -> None
self.mem = mem
self.cmd_ev = cmd_ev # To run blocks

def _GetContext(self):
# type: () -> Dict[str, value_t]
ctx = self.mem.GetContext()
if ctx is None:
raise error.Expr(
"Could not find a context. Did you forget to 'ctx push'?",
loc.Missing)
return ctx

def _Push(self, context, block):
# type: (Dict[str, value_t], command_t) -> int
with ctx_Context(self.mem, context):
return self.cmd_ev.EvalCommand(block)

def _Set(self, updates):
# type: (Dict[str, value_t]) -> int
ctx = self._GetContext()
ctx.update(updates)
return 0

def _Emit(self, field, item, blame):
# type: (str, value_t, loc_t) -> int
ctx = self._GetContext()

if field not in ctx:
ctx[field] = value.List([])

UP_arr = ctx[field]
if UP_arr.tag() != value_e.List:
raise error.TypeErr(
UP_arr,
"Expected the context item '%s' to be a List" % (field), blame)

arr = cast(value.List, UP_arr)
arr.items.append(item)

return 0

def Run(self, cmd_val):
# type: (cmd_value.Argv) -> int
rd = typed_args.ReaderForProc(cmd_val)
_, arg_r = flag_util.ParseCmdVal('ctx',
cmd_val,
accept_typed_args=True)

verb, verb_loc = arg_r.ReadRequired2(
'Expected a verb (push, set, emit)')

if verb == "push":
context = rd.PosDict()
block = rd.RequiredBlock()
rd.Done()
arg_r.AtEnd()

return self._Push(context, block)

elif verb == "set":
updates = rd.RestNamed()
rd.Done()
arg_r.AtEnd()

return self._Set(updates)

elif verb == "emit":
field, field_loc = arg_r.ReadRequired2(
"A target field is required")
item = rd.PosValue()
rd.Done()
arg_r.AtEnd()

return self._Emit(field, item, field_loc)

else:
raise error.Usage("Unknown verb '%s'" % verb, verb_loc)


class PushRegisters(vm._Builtin):

def __init__(self, mem, cmd_ev):
Expand Down
1 change: 0 additions & 1 deletion core/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,6 @@ def Main(
b[builtin_i.trap] = trap_osh.Trap(trap_state, parse_ctx, tracer, errfmt)

b[builtin_i.shvar] = pure_ysh.Shvar(mem, search_path, cmd_ev)
b[builtin_i.ctx] = pure_ysh.Ctx(mem, cmd_ev)
b[builtin_i.push_registers] = pure_ysh.PushRegisters(mem, cmd_ev)

# Hay
Expand Down
1 change: 0 additions & 1 deletion frontend/builtin_def.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
'fork', 'forkwait',
'redir', 'fopen', # fopen is for backward compat
'shvar',
'ctx',

'invoke',
'runproc',
Expand Down
15 changes: 15 additions & 0 deletions spec/ysh-builtin-ctx.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
## oils_failures_allowed: 0

#### ctx push and set
use $LIB_YSH/ctx.ysh

var mydict = {}
ctx push (mydict) {
ctx set (key1="value1")
Expand All @@ -16,6 +18,8 @@ json write (mydict)
## END

#### ctx emit
use $LIB_YSH/ctx.ysh

var p = {}
ctx push (p) {
ctx emit flag ({short_name: '-v'})
Expand Down Expand Up @@ -58,6 +62,8 @@ json write (p)
## END

#### nested ctx
use $LIB_YSH/ctx.ysh

var a = {}
var b = {}
ctx push (a) {
Expand All @@ -78,6 +84,8 @@ json write (b)
## END

#### error in context
use $LIB_YSH/ctx.ysh

var a = {}
try {
ctx push (a) {
Expand All @@ -91,20 +99,26 @@ status=100
## END

#### no context, set
use $LIB_YSH/ctx.ysh

ctx set (bad=true)
echo status=$_status
## status: 3
## STDOUT:
## END

#### no context, emit
use $LIB_YSH/ctx.ysh

ctx emit bad (true)
echo status=$_status
## status: 3
## STDOUT:
## END

#### mini-parseArgs
use $LIB_YSH/ctx.ysh

proc parser (; place ; ; block_def) {
var p = {}
ctx push (p; ; block_def)
Expand Down Expand Up @@ -159,6 +173,7 @@ json write (spec)
## END

#### ctx with value.Place, not List/Dict (error location bug fix)
use $LIB_YSH/ctx.ysh

ctx push (&p) {
true
Expand Down
2 changes: 2 additions & 0 deletions stdlib/ysh/args.ysh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#
# echo "Verbose $[args.verbose]"

source $LIB_YSH/ctx.ysh

# TODO: See list
# - It would be nice to keep `flag` and `arg` private, injecting them into the
# proc namespace only within `Args`
Expand Down
32 changes: 32 additions & 0 deletions stdlib/ysh/ctx.ysh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
var contextStack = []

proc push (; context;; block) {
if (type(context) !== 'Dict') {
error "Expected context to be a Dict" (code=3)
}

call contextStack->append(context)
try {
use ///ysh/ctx.ysh
call io->eval(block, vars={ctx})
}
call contextStack->pop()
return $[_error.code]
}

proc set (;; ...named) {
var context = contextStack[-1]
for k, v in (named) {
setvar context[k] = v
}
}

proc emit (field; item) {
var context = contextStack[-1]
if (field not in context) {
setvar context[field] = []
}
call context[field]->append(item)
}

var __provide__ = :| push set emit |
Loading