Skip to content

node-bash/bash-tree

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

The BashTree Spec

Node Objects

interface Node {
  type: string
  loc: SourceLocation | null
}
interface SourceLocation {
  source: string | null
  start: Position
  end: Position
}
interface Position {
  line: number   // 1-indexed
  column: number // 0-indexed
}

Identifier

interface Identifier : Node {
  type: "Identifier"
  name: string
}

Program

interface Program : Node {
  type: "Program"
  body: BlockStatement
}

The whole bash program tree

BlockStatement

interface BlockStatement : Node {
  type: "BlockStatement"
  body: [ Statement ]
}

Redirection

TestOperation

interface TestOperation {
  type: "TestOperation"
  operator: FileTestOperator | TestOperator
  left: Expression | null
  right: Expression
}
enum FileTestOperator {
  // TODO
  "-e"
}
enum TestOperator {
  // TODO
  "-eq"
}

HereDocument

interface HereDocument {
  type: "HereDocument"
  limitString: string
  // TODO: maybe substitution should be down at runtime, not at compiling
  documents: [ Literal | Substitution ]
  suppressLeadingTabs: boolean
  enableSubstitution: boolean
}

ArithmeticOperation

UnaryOperation

interface UnaryOperation : ArithmeticOperation {
  type: "UnaryOperation"
  operator: UnaryOperator
  prefix: boolean
  argument: Identifier
}
enum UnaryOperator {
  "-"
}

UpdateOperation

interface UpdateOperation : ArithmeticOperation {
  type: "UpdateOperation"
  operator: UpdateOperator
  argument: Identifier
  prefix: boolean
}
enum UpdateOperator {
  "++" | "--"
}

BinaryOperation

interface BinaryOperation : ArithmeticOperation {
  type: "BinaryOperation"
  operator: BinaryOperator
  left: Identifier
}
enum BinaryOperator {
  // TODO: more
  "+" | "-" | "*" | "/" |
  "**" | "%" |
  "+=" | "-=" | "*=" | "/=" | "%=" |
  "<<" | "<<=" | ">>" | ">>=" | "&" | "&=" | "|" | "|=" | "~" | "^" | "^="
  ">" | "<"
}

ConditionalOperation

// Ternary
interface ConditionalOperation : ArithmeticOperation {
  type: "TernaryOperation"
  test: ArithmeticOperation
  alternate: Literal | ArithmeticOperation
  consequent: Literal | ArithmeticOperation
}

LogicalOperation

interface LogicalOperation : ArithmeticOperation {
  type: "LogicalOperation"
  operator: LogicalOperator
  left: ArithmeticOperation || null
  right: ArithmeticOperation
}
enum LogicalOperator {
  "||" | "&&" || "!"
}

Statement

interface Statement : Node {}

A statement is a thing that can stand alone.

SubShell

interface SubShell : Statement {
  type: "SubShell"
  body: BlockStatement
}

ArithmeticStatement

// ((  ))
interface ArithmeticStatement : Statement {
  type: "ArithmeticStatement"
  operation: ArithmeticOperation
}

Control Flow

Choice

IfStatement

interface IfStatement : Statement {
  type: "IfStatement"
  test: ArithmeticStatement | Command | TestConstruct
  consequent: BlockStatement
  alternate: Statement | null
  kind: "elif" | "else if" | null
}

CaseStatement

FunctionDeclaration

interface FunctionDeclaration : Statement {
  type: "FunctionDeclaration"
  id: Identifier
  body: [ Statement ]
}

A function declaration

VariableAssignment

interface VariableAssignment : Statement {
  type: "VariableAssignment"
  // a=1 | a[1]=1
  left: Identifier | ArrayMemberConstruct
  right: Expression
}

VariableDeclaration (?)

interface VariableDeclaration : Statement {
  type: "VariableDeclaration"
  id: Identifier
  // declare -a a=1
  kind: "a" | "i" | "r" | "local"
  init: Expression | null
}

Actually declare -a a=foo is a command, but it is better to be treated as a Statement due to its complication.

Command

interface Command : Statement {
  type: "Command"
  name: string
  argv: Arguments
}

Arguments

interface Arguments {
  type: "Arguments"
  args: [ Expression ]
}

The length of the arguments depends on the result of substitution

Construct

interface Construct : Node {}

ArrayMemberConstruct

interface MemberConstruct : Construct {
  type: "ArrayMemberConstruct"
  array: Identifier
  property: Literal
}

TestConstruct

interface TestConstruct {
  type: "TestConstruct"
  condition: Expression |
  // [] | [[]]
  kind: "test" | "extended"
}

Expansion

BraceExpansion

interface BraceExpansion : Expansion {
  type: "BraceExpansion"
  expansions: [ Literal ]
  prefix: Literal | Expansion
  suffix: Literal
}

ExtendedBraceExpansion

// {a..z}
interface ExtendedBraceExpansion : Expansion {
  type: "ExtendedBraceExpansion"
  start: Literal
  end: Literal
  // foo{a..z} | {1..9}{a..z}
  prefix: Literal | Expansion
  suffix: Literal
}

Expression

interface Expression : Node {}

An expression is what can be assigned to identifiers or as the item of arguments.

Literal

interface Literal : Expression {
  type: "Literal"
  // 'a'
  value: string
  // '"a"'
  raw: string
}

ArrayExpression

interface ArrayExpression : Expression {
  type: "ArrayExpression"
  elements: Arguments
}

Substitution

CommandSubstitution

interface CommandSubstitution : Expression {
  type: "CommandSubstitution"
  command: Command
  // `command -r` | $(command -r)
  kind: "backtick" | "bracket"
}

StringSubstitution

// "$a"
interface StringSubstitution : Expression {
  type: "StringSubstitution"
  contents: [ Literal | VariableSubstitution ]
}

VariableSubstitution

// ${a:-default}
interface VariableSubstitution : Expression {
  type: "VariableSubstitution"
  kind: "brace" | "no-brace"
  // null for positional variables
  id: Identifier | null
  pattern: VariableDirective | null
}

ArithmeticSubstitution

// $(( 2 + 3))
interface ArithmeticSubstitution : Expression {
  type: "ArithmeticSubstitution"
  content: ArithmeticStatement
}

ProcessSubstitution

interface ProcessSubstitution : Expression {
  type: "ProcessSubstitution"
  command: Command
  // >() | <()
  kind: "in" | "out"
}

VariableDirective

MemberAccessDirective

interface MemberAccessDirective : VariableDirective {
  type: "MemberAccessDirective"
  property: Literal
}

GetterDirective

// value[kind]arg
interface GetterDirective : VariableDirective {
  type: "GetterDirective"
  kind: "-" | ":-" | "=" | ":=" | "+" | ":+" | "?" | ":?"
  arg: Literal | Expression
}

LengthDirective

// #value[property]
interface LengthDirective : VariableDirective {
  type: "LengthDirective"
  property: "*" | "@" | null
}

CropDirective

// value[kind]pattern
interface CropDirective : VariableDirective {
  type: "CropDirective"
  pattern: Literal | Expression
  kind: "#" | "##" | "%" | "%%"
}

SliceDirective

// value:start[:end]
interface SliceDirective : VariableDirective {
  type: "SliceDirective"
  start: Literal
  end: Literal | null
}

ReplaceDirective

// value/[kind]pattern/replacement
interface ReplaceDirective : VariableDirective {
  type: "ReplaceDirective"
  pattern: Literal
  replacement: Literal
  kind: "/" | "#" | "%" | null
}

SearchDirective

// !value[kind]
interface SearchDirective : VariableDirective {
  type: "SearchDirective"
  // the same
  kind: "*" | "@"
}