Skip to content

Commit

Permalink
[osh-language] Spec tests for associative arrays.
Browse files Browse the repository at this point in the history
- dparen
- assign-dialects

Start documenting the data model.

Related to #294 and #300.

Somewhat related to #207, #236, and #287.
  • Loading branch information
Andy Chu committed Jul 13, 2019
1 parent 919298c commit 7d79aad
Show file tree
Hide file tree
Showing 7 changed files with 594 additions and 37 deletions.
326 changes: 326 additions & 0 deletions doc/osh-data-model.md
@@ -0,0 +1,326 @@
OSH Data Model
--------------

- This is for the OSH language, as opposed to the Oil language.
- OSH semantics are based on:
- POSIX shell for strings
- bash and ksh for arrays and associative arrays. bash largely follows ksh
is the case of arrays. Its associative arrays are quickier.

POSIX shell for strings
exisbash. For

Python coercions.

TODO:

- Use fenced code blocks
- and then evaluate like Pulp
- maybe borrow from Brett
- and run through BOTH bash and osh
- and link to this doc

- bash 4.3 maybe? or 4.4

### Why Use this Information?

The goal of Oil is to replace this quirkl language! But we still made it
compatible.

If you want to write scripts compatible with OSH and bash!

TODO: The Oil language not done yet!


### Preliminary: Why Differences from bash

I SALVAGED THESE SEMANTICS.

Worst of the language! Newest and most "grafted on".


#### Surprising Parsing

Parsing bash is undecidable.

A[x]
a[x]

#### Surprising Coercions

Horrible

a=('1 2' 3)
b=(1 '2 3') # two different elements

[[ $a == $b ]]
[[ ${a[0]} == ${b[0]} ]]

[[ ${a[@]} == ${b[@]} ]]


Associative arrays and being undefined

- half an array type
- strict-array removes this
- case $x in "$@"

- half an associative array type

#### Bugs

- test -v
- empty array and nounset, in bash 4.3. I can't recommend in good faith



### Undef, Str, Sequential/Indexed Arrays, Associative Array

- "array" refers to both.
- although Oil has a "homogeneous array type" that's entirely different
- OSH array vs. Oil array

- no integers, but there is (( ))

- "$@" is an array, and "${a[@]}" too
- not true in bash -- it's fuzzy there

- but $@ and ${a[@]} are NOT arrays
- flags: readonly and exported (but arrays/assoc arrays shouldn't be exported)
- TODO: find that

#### Arrays Can't Be Nested and Can't Escape Functions

Big limitation! Lifting it in Oil

You have to splice

There's no Garbage collection.

#### There are no true integers

There are lots of coercions instead.

bash has '-i' but that's true anyway.


### Operations on All Variables

#### assignment

#### unset

#### readonly

#### export only applies to strings


### Operations on Arrays

#### Initialization

declare -a array
declare -a array=()

declare -A assoc
# there is no empty literal here

Also valid, but not necessary since `declare` is local:

local -a array
local -A assoc

Makes a global array:

array=()

#### Array Literals

Respects the normal rules of argv.

prefix=foo
myarray=(one two -{three,four}- {5..8} *.py "$prefix*.py" '$prefix*.py')

myarray=(
$var ${var} "$var"
$(echo hi) "$(echo hi)"
$(1 + 2 * 3)
)

#### "${a[@]}" is Evaluating (Splicing)

echo "${array[@]}"
echo "${assoc[@]}"

NOT Allowed, unlike in bash!

$assoc ${assoc} "${assoc}"
${!assoc} ${assoc//pattern/replace} # etc.


#### Iteration

Note that since a for loop takes an array of words, evaluating/splicing works:

for i in "${a1[@]}" "${a2[@]}"; do
echo $i
done

#### ${#a[@]} is the Length


echo ${#array[@]}
echo ${#assoc[@]}



#### Coercion to String by Joining Elements

echo ${!array[@]}
echo ${!assoc[@]}

echo ${!array[*]}
echo ${!assoc[*]}

echo "${!array[*]}"
echo "${!assoc[*]}"

#### Look Up By Index / Key With a[]

matrix:
a['x'] a["x"]
a["$x"]
a[$x]

a[x] -- allowed
A[x] -- NOT allowed? It should be a string

(( 'a' )) -- parsed, but can't evaluate

# This is a string in both cases
a[0]
A[0]


undef[0]=1 automatically creates an INDEXED array
undef=(1)

#### Assign / Append To Location Specified by Index / Key

a[expr]= # int_coerce
A[expr]= # no integer coercion

Just like you can append to strings:

s+='foo'

Append to elements of an array, which are strings:

a[x+1]+=x
a[x+1]+=$x

#### Slicing With ${a[@]:5:2}

${array[@]:1:3}

Note the presence of DISALLOWED VALUES.


# TODO: disallow this? because no order
${assoc[@]:1:3}


NOTE: string slicing:



#### Append Array to Array

a=(1 2 3)
a+=(4 5 6)


#### Get All Indices With ${!a[@]}

echo ${!array[@]}
echo ${!assoc[@]}


#### Vectorized String Operations

echo ${array[@]//x/X}

echo ${assoc[@]//x/X}


### Strict Options

set -o nounset # bash

shopt -s strict-array
shopt -s strict-arith # on by default

shopt -s strict-word-eval # slice args, unicode strings


### Quirky Syntax and Semantics in Shell Sublanguages

#### Command

Mentioned above:

a[x+1]+=x
a[x+1]+=$x

s+='foo'

#### Word

Mentioned above:

echo ${a[0]}
echo "${a[0]}"
echo ${a[i+1]}

#### Arithmetic Does Integer Coercion

SURPRISING! Avoid if you can!!!

(( a[ x+1 ] += s )) #


#### Boolean: [[ $a = $b ]]

Operates on strings only. Can't compare

### Introspection

#### set

Prints all variables. Strings only?

#### declare/typeset/readonly/export -p

Prints a subset.

#### test -v

Test if a variable is defined.

Don't use this because it's incopmatible?

#### repr (OSH-specific)

### Future Work: The Oil Data Model

- similar to Python and JavaScript
- garbage collection
- JSON serialization


### Links

- <https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays>
- <https://www.thegeekstuff.com/2010/06/bash-array-tutorial>


8 changes: 7 additions & 1 deletion osh/cmd_exec.py
Expand Up @@ -406,7 +406,13 @@ def _CheckStatus(self, status, node):
span_id=span_id, status=status)

def _EvalLhs(self, node, spid, lookup_mode):
"""lhs_expr -> lvalue."""
"""lhs_expr -> lvalue.
Used for a=b and a[x]=b
TODO: Rationalize with expr_eval EvalLhsAndLookup, which is used for a+=b
and a[x]+=b.
"""
assert isinstance(node, lhs_expr_t), node

if node.tag == lhs_expr_e.LhsName: # a=x
Expand Down

0 comments on commit 7d79aad

Please sign in to comment.