Permalink
Browse files

[osh2oil] Overhaul the translation of assignments.

There is no longer a := operator.

We just have var, set, const, and setglobal.

Also:
- tests for EmptyWordPart
  • Loading branch information...
Andy Chu
Andy Chu committed Aug 26, 2018
1 parent 590e137 commit a181a33118bca9dc4fbb3eefc75517ed4b28a351
Showing with 109 additions and 37 deletions.
  1. +97 −24 test/osh2oil.sh
  2. +12 −13 tools/osh2oil.py
View
@@ -111,9 +111,17 @@ OIL
suffix-ops() {
osh0-oil3 << 'OSH' 3<< 'OIL'
echo ${s:-3} ${s##suffix}
echo ${s:-3}
echo ${s:-}
echo ${s:-''}
echo ${s:-""}
echo ${s##suffix}
OSH
echo $(s or 3) $s.trimRight('suffix')
echo $(s or '3')
echo $(s or '')
echo $(s or '')
echo $(s or "")
echo $s.trimRight('suffix')
OIL
}
@@ -318,55 +326,120 @@ env FOO=$(bar) BAR=$[echo hi] echo 2
OIL
}
assign-common() {
# top level
osh-to-oil --fix -c 'foo=bar spam="$var"'
osh-to-oil --fix -c 'readonly foo=bar spam="${var}"'
osh-to-oil --fix -c 'export foo=bar spam="${var}/const"'
assign2() {
osh0-oil3 << 'OSH' 3<< 'OIL'
foo=bar spam="$var"
OSH
setglobal foo = 'bar', spam = $var
OIL
osh0-oil3 << 'OSH' 3<< 'OIL'
readonly foo=bar spam="${var}"
OSH
const foo = 'bar', spam = $(var)
OIL
osh0-oil3 << 'OSH' 3<< 'OIL'
f() {
local foo=bar spam=eggs
foo=mutated
g=new
}
OSH
proc f {
var foo = 'bar', spam = 'eggs'
set foo = 'mutated'
setglobal g = 'new'
}
OIL
return
# Inside function
osh-to-oil --fix -c 'f() { foo=bar spam=${var:-default}; }'
osh-to-oil --fix -c 'f() { local foo=bar spam=eggs; foo=mutated; g=new; }'
osh0-oil3 << 'OSH' 3<< 'OIL'
f() { foo=bar spam=${var:-default}; }
OSH
proc f { setglobal foo = 'bar', spam = $(var or 'default'); }
OIL
# TODO:
# - Test everything without a RHS. export and readonly
# - Print RHS as expression
# - declare -- but this is more rare. declare is usually 'var'.
}
# NOTE: This is probably wrong
export-case() {
osh0-oil3 << 'OSH' 3<< 'OIL'
export foo=bar spam="${var}/const"
OSH
export foo=bar spam="$(var)/const"
OIL
}
# , and ; are similar.
assign() {
# global variable. Since we don't know if it's sourced, turn it into
# 'setglobal'.
osh0-oil3 << 'OSH' 3<< 'OIL'
local foo=$(basename $1)
g=
g=x
OSH
var foo = $[basename $1]
setglobal g = ''
setglobal g = 'x'
OIL
# Local variable
osh0-oil3 << 'OSH' 3<< 'OIL'
f() {
local foo=$(basename $1)
}
OSH
proc f {
var foo = $[basename $1]
}
OIL
return
# More than one local on a line
osh0-oil3 << 'OSH' 3<< 'OIL'
f() {
local one=1 two three=3
}
OSH
proc f {
var one = '1', two = '', three = '3'
}
OIL
# local that is mutated
osh0-oil3 << 'OSH' 3<< 'OIL'
local one=1 two three=3
f() {
local one=1 two
one=x
two=y
g=z
}
OSH
one = '1', two = '', three = '3'
proc f {
var one = '1', two = ''
set one = 'x'
set two = 'y'
setglobal g = 'z'
}
OIL
# Top-level constant
osh0-oil3 << 'OSH' 3<< 'OIL'
myStr=one
readonly myConstStr=two
OSH
var myStr = 'hi'
myConstStr = 'hi'
const myConstStr = 'two'
OIL
# Local constant
osh0-oil3 << 'OSH' 3<< 'OIL'
f() {
local myStr=one
readonly myConstStr=two
}
OSH
proc f {
var myStr = 'hi'
myConstStr = 'hi'
var myStr = 'one'
const myConstStr = 'two'
}
OIL
@@ -378,7 +451,7 @@ f() {
OSH
proc f {
var myStr = $1
myConstStr = $(1 + 2)
const myConstStr = $(1 + 2)
}
OIL
}
View
@@ -397,19 +397,13 @@ def DoAssignment(self, node, at_top_level, local_symbols):
# need semantic analysis.
# Would be nice to assume that it's a local though.
if at_top_level:
self.f.write('global ') # can't be redefined
new_assign_op_e = '::='
#self.f.write('global TODO := TODO') # mutate global or define it
self.f.write('setglobal ')
elif defined_locally:
new_assign_op_e = ':=' # assume mutation of local
self.f.write('set ')
#self.f.write('[local mutated]')
else:
# we're in a function, but it's not defined locally.
self.f.write('global ') # assume mutation of local
if self.mode == PEDANTIC: # assume globals defined
new_assign_op_e = '::='
else:
new_assign_op_e = ':='
self.f.write('setglobal ') # assume mutation of local
elif node.keyword == Id.Assign_Readonly:
# Explicit const. Assume it can't be redefined.
@@ -425,11 +419,14 @@ def DoAssignment(self, node, at_top_level, local_symbols):
if at_top_level:
self.cursor.PrintUntil(keyword_spid)
self.cursor.SkipUntil(keyword_spid + 1)
self.f.write('const') # can't be redefined
self.f.write('const')
elif defined_locally:
self.f.write('setconst FOO = "bar"')
raise RuntimeError("Constant redefined locally")
else:
self.f.write('setconst global FOO = "bar"')
# Same as global level
self.cursor.PrintUntil(keyword_spid)
self.cursor.SkipUntil(keyword_spid + 1)
self.f.write('const')
elif node.keyword == Id.Assign_Declare:
# declare -rx foo spam=eggs
@@ -459,6 +456,8 @@ def DoAssignment(self, node, at_top_level, local_symbols):
# foo=bar -> foo = 'bar'
#print('RHS', pair.rhs, file=sys.stderr)
# TODO: This should be translated from EmptyWord.
if pair.rhs is None:
self.f.write("''") # local i -> var i = ''
else:
@@ -472,7 +471,7 @@ def DoCommand(self, node, local_symbols, at_top_level=False):
# TODO: How to distinguish between echo hi; echo bye; and on separate
# lines
for child in node.children:
self.DoCommand(child, local_symbols)
self.DoCommand(child, local_symbols, at_top_level=at_top_level)
elif node.tag == command_e.SimpleCommand:
# How to preserve spaces between words? Do you want to do it?

0 comments on commit a181a33

Please sign in to comment.