Skip to content

Commit 28aad3d

Browse files
committed
Start struct assignment implementation (#51)
1 parent efa6d1f commit 28aad3d

7 files changed

Lines changed: 229 additions & 68 deletions

File tree

converters/bash/converter.go

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,31 @@ import (
99
"github.com/monstermichl/typeshell/transpiler"
1010
)
1111

12+
type helperName = string
13+
14+
const (
15+
sliceAssignmentHelper helperName = "_sah" // Slice assignment
16+
sliceCopyHelper helperName = "_sch" // Slice copy
17+
structAssignmentHelper helperName = "_stah" // Struct assignment
18+
stringSubscriptHelper helperName = "_stsh" // String subscript
19+
)
20+
1221
type funcInfo struct {
1322
name string
1423
}
1524

1625
type converter struct {
17-
interpreter string
18-
startCode []string
19-
code []string
20-
varCounter int
21-
forCounter int
22-
funcs []funcInfo
23-
funcCounter int
24-
sliceAssignmentHelperRequired bool
25-
sliceCopyHelperRequired bool
26-
stringSubscriptHelperRequired bool
26+
interpreter string
27+
startCode []string
28+
code []string
29+
varCounter int
30+
forCounter int
31+
funcs []funcInfo
32+
funcCounter int
33+
sliceAssignmentHelperRequired bool
34+
structAssignmentHelperRequired bool
35+
sliceCopyHelperRequired bool
36+
stringSubscriptHelperRequired bool
2737
}
2838

2939
func New() *converter {
@@ -62,7 +72,7 @@ func (c *converter) ProgramEnd() error {
6272
// $2: Assignment index
6373
// $3: Assignment value
6474
// $4: Default value
65-
c.addHelper("slice assignment", "_sah",
75+
c.addHelper("slice assignment", sliceAssignmentHelper,
6676
"local _i=${2}",
6777
fmt.Sprintf(`local _l=%s`, c.sliceLenString("${1}")),
6878
`for ((_c=${_l};_c<${_i};_c++)); do`,
@@ -73,7 +83,7 @@ func (c *converter) ProgramEnd() error {
7383
}
7484

7585
if c.sliceCopyHelperRequired {
76-
c.addHelper("slice copy", "_sch",
86+
c.addHelper("slice copy", sliceCopyHelper,
7787
"local _i=0",
7888
fmt.Sprintf(`local _l=%s`, c.sliceLenString("${2}")),
7989
"local _n=$(eval \"echo \\${${1}}\")",
@@ -85,8 +95,17 @@ func (c *converter) ProgramEnd() error {
8595
)
8696
}
8797

98+
if c.structAssignmentHelperRequired {
99+
// $1: Slice name
100+
// $2: Assignment field
101+
// $3: Assignment value
102+
c.addHelper("struct assignment", structAssignmentHelper,
103+
c.sliceAssignmentString("${1}", "${2}", "${3}", false),
104+
)
105+
}
106+
88107
if c.stringSubscriptHelperRequired {
89-
c.addHelper("substring", "_ssh",
108+
c.addHelper("substring", stringSubscriptHelper,
90109
`_ls=$((${2}))`,
91110
`_ll=$(((${3}-${2})+1))`,
92111
`_ret="${1:${_ls}:${_ll}}"`,
@@ -106,7 +125,13 @@ func (c *converter) VarAssignment(name string, value string, global bool) error
106125

107126
func (c *converter) SliceAssignment(name string, index string, value string, defaultValue string, global bool) error {
108127
c.sliceAssignmentHelperRequired = true
109-
c.addLine(fmt.Sprintf(`_sah %s %s "%s" "%s"`, c.varEvaluationString(name, global), index, value, defaultValue))
128+
c.callFunc(sliceAssignmentHelper, c.varEvaluationString(name, global), index, value, defaultValue)
129+
return nil
130+
}
131+
132+
func (c *converter) StructAssignment(name string, field string, value string, global bool) error {
133+
c.structAssignmentHelperRequired = true
134+
c.callFunc(structAssignmentHelper, c.varEvaluationString(name, global), field, value)
110135
return nil
111136
}
112137

@@ -418,7 +443,7 @@ func (c *converter) StructDefinition(values []transpiler.StructValue, valueUsed
418443
func (c *converter) StringSubscript(value string, startIndex string, endIndex string, valueUsed bool) (string, error) {
419444
helper := c.nextHelperVar()
420445

421-
c.addLine(fmt.Sprintf(`_ssh "%s" %s %s`, value, startIndex, endIndex))
446+
c.callFunc(stringSubscriptHelper, value, startIndex, endIndex)
422447
c.VarAssignment(helper, c.varEvaluationString("_ret", true), false) // https://www.baeldung.com/linux/bash-substring#1-using-thecut-command
423448
c.stringSubscriptHelperRequired = true
424449

@@ -518,7 +543,7 @@ func (c *converter) Input(prompt string, valueUsed bool) (string, error) {
518543
func (c *converter) Copy(destination string, source string, valueUsed bool, global bool) (string, error) {
519544
destination = c.varName(destination, global)
520545

521-
c.addLine(fmt.Sprintf("_sch %s %s", destination, source))
546+
c.callFunc(sliceCopyHelper, destination, source)
522547
c.sliceAssignmentHelperRequired = true
523548
c.sliceCopyHelperRequired = true
524549

@@ -548,6 +573,10 @@ func (c *converter) ReadFile(path string, valueUsed bool) (string, error) {
548573
return c.VarEvaluation(helper, valueUsed, false)
549574
}
550575

576+
func (c *converter) callFunc(name string, args ...string) {
577+
c.addLine(fmt.Sprintf(`%s "%s"`, name, strings.Join(args, `" "`)))
578+
}
579+
551580
func (c *converter) mustCurrentForVar() string {
552581
return fmt.Sprintf("_fv%d", c.forCounter)
553582
}

converters/batch/converter.go

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,18 @@ import (
1313
type helperName = string
1414

1515
const (
16-
appCallHelper helperName = "_ach" // App call
17-
fileReadHelper helperName = "_frh" // File write
18-
fileWriteHelper helperName = "_fwh" // File read
19-
sliceLenSetHelper helperName = "_sls" // Slice length set
20-
sliceLenGetHelper helperName = "_slg" // Slice length get
21-
sliceAssignmentHelper helperName = "_sah" // Slice assignment
22-
sliceCopyHelper helperName = "_sch" // Slice copy
23-
stringSubscriptHelper helperName = "_stsh" // String subscript
24-
stringLengthHelper helperName = "_stlh" // String length
25-
stringEscapeHelper helperName = "_seh" // String escape
26-
echoHelper helperName = "_ech" // Echo
16+
appCallHelper helperName = "_ach" // App call
17+
fileReadHelper helperName = "_frh" // File write
18+
fileWriteHelper helperName = "_fwh" // File read
19+
sliceLenSetHelper helperName = "_sls" // Slice length set
20+
sliceLenGetHelper helperName = "_slg" // Slice length get
21+
sliceAssignmentHelper helperName = "_sah" // Slice assignment
22+
sliceCopyHelper helperName = "_sch" // Slice copy
23+
structAssignmentHelper helperName = "_stah" // Struct assignment
24+
stringSubscriptHelper helperName = "_stsh" // String subscript
25+
stringLengthHelper helperName = "_stlh" // String length
26+
stringEscapeHelper helperName = "_seh" // String escape
27+
echoHelper helperName = "_ech" // Echo
2728
)
2829

2930
type funcInfo struct {
@@ -39,31 +40,32 @@ type ifInfo struct {
3940
}
4041

4142
type converter struct {
42-
startCode []string
43-
helperCode []string
44-
globalCode []string
45-
previousFunctionName string
46-
functionsCode [][]string
47-
endCode []string
48-
varCounter int
49-
ifCounter int
50-
forCounter int
51-
endLabels []string
52-
funcs []funcInfo
53-
funcCounter int
54-
fors []forInfo
55-
ifs []ifInfo
56-
lfSet bool
57-
appCallHelperRequired bool
58-
readHelperRequired bool
59-
sliceAssignmentHelperRequired bool
60-
sliceCopyHelperRequired bool
61-
sliceLenSetHelperRequired bool
62-
sliceLenGetHelperRequired bool
63-
stringSubscriptHelperRequired bool
64-
stringLenHelperRequired bool
65-
fileWriteHelperRequired bool
66-
echoHelperRequired bool
43+
startCode []string
44+
helperCode []string
45+
globalCode []string
46+
previousFunctionName string
47+
functionsCode [][]string
48+
endCode []string
49+
varCounter int
50+
ifCounter int
51+
forCounter int
52+
endLabels []string
53+
funcs []funcInfo
54+
funcCounter int
55+
fors []forInfo
56+
ifs []ifInfo
57+
lfSet bool
58+
appCallHelperRequired bool
59+
readHelperRequired bool
60+
sliceAssignmentHelperRequired bool
61+
structAssignmentHelperRequired bool
62+
sliceCopyHelperRequired bool
63+
sliceLenSetHelperRequired bool
64+
sliceLenGetHelperRequired bool
65+
stringSubscriptHelperRequired bool
66+
stringLenHelperRequired bool
67+
fileWriteHelperRequired bool
68+
echoHelperRequired bool
6769
}
6870

6971
func New() *converter {
@@ -184,7 +186,6 @@ func (c *converter) ProgramEnd() error {
184186
if c.sliceAssignmentHelperRequired {
185187
c.sliceLenGetHelperRequired = true
186188
c.sliceLenSetHelperRequired = true
187-
c.sliceAssignmentHelperRequired = true
188189

189190
// %1: Slice name
190191
// %2: Assigned index
@@ -218,6 +219,15 @@ func (c *converter) ProgramEnd() error {
218219
)
219220
}
220221

222+
if c.structAssignmentHelperRequired {
223+
// %1: Slice name
224+
// %2: Assigned field
225+
// arg0: Assigned value
226+
c.addHelper("struct assignment", structAssignmentHelper,
227+
c.sliceAssignmentString("!%1!", "%2", fmt.Sprintf("!%s!", funcArgVar(0)), false),
228+
)
229+
}
230+
221231
if c.stringSubscriptHelperRequired {
222232
c.addHelper("string subscript", stringSubscriptHelper,
223233
`set /A "_sh=(%2-%1)+1"`,
@@ -263,6 +273,12 @@ func (c *converter) SliceAssignment(name string, index string, value string, def
263273
return nil
264274
}
265275

276+
func (c *converter) StructAssignment(name string, field string, value string, global bool) error {
277+
c.structAssignmentHelperRequired = true
278+
c.callFunc(structAssignmentHelper, []string{value}, c.varName(name, global), field)
279+
return nil
280+
}
281+
266282
func (c *converter) FuncStart(name string, params []string, returnTypes []parser.ValueType) error {
267283
c.funcCounter++
268284
c.funcs = append(c.funcs, funcInfo{

parser/parser.go

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,10 @@ func defaultVarValue(valueType ValueType, ctx context) (Expression, error) {
436436
return nil, err
437437
}
438438
structValues = append(structValues, StructValue{
439-
name: field.Name(),
439+
StructField: StructField{
440+
name: field.Name(),
441+
valueType: field.ValueType(),
442+
},
440443
value: defaultValue,
441444
})
442445
}
@@ -2843,20 +2846,26 @@ func (p *Parser) evaluateStatement(ctx context) (Statement, error) {
28432846
} else {
28442847
// If token is identifier it could be a slice assignment, an increment or a decrement.
28452848
if token.Type() == lexer.IDENTIFIER {
2846-
switch p.peekAt(1).Type() {
2849+
switch nextTokenType := p.peekAt(1).Type(); nextTokenType {
28472850
case lexer.INCREMENT_OPERATOR, lexer.DECREMENT_OPERATOR:
28482851
stmt, err = p.evaluateIncrementDecrement(ctx)
28492852
case lexer.COMPOUND_ASSIGN_OPERATOR:
28502853
stmt, err = p.evaluateCompoundAssignment(ctx)
28512854
case lexer.ASSIGN_OPERATOR, lexer.COMMA:
28522855
stmt, err = p.evaluateVarAssignment(ctx)
28532856
default:
2854-
// Handle slice assignment.
28552857
variable, exists := ctx.findNamedValue(token.Value(), p.prefix, ctx.global())
28562858

2857-
// If variable has been defined and is a slice, handles slice assignment.
2858-
if exists && variable.ValueType().IsSlice() {
2859-
stmt, err = p.evaluateSliceAssignment(ctx)
2859+
switch nextTokenType {
2860+
case lexer.DOT:
2861+
// Could be a library variable or a struct assignment.
2862+
// TODO: Handle library stuff as well, but for now handle struct assignment.
2863+
stmt, err = p.evaluateStructAssignment(ctx)
2864+
default:
2865+
// If variable has been defined and is a slice, handles slice assignment.
2866+
if exists && variable.ValueType().IsSlice() {
2867+
stmt, err = p.evaluateSliceAssignment(ctx)
2868+
}
28602869
}
28612870
}
28622871
}
@@ -3397,6 +3406,79 @@ func (p *Parser) evaluateSliceAssignment(ctx context) (Statement, error) {
33973406
}, nil
33983407
}
33993408

3409+
func (p *Parser) evaluateStructAssignment(ctx context) (Statement, error) {
3410+
nameToken := p.eat()
3411+
3412+
if nameToken.Type() != lexer.IDENTIFIER {
3413+
return nil, p.expectedError("struct variable", nameToken)
3414+
}
3415+
name := nameToken.Value()
3416+
namedValue, exists := ctx.findNamedValue(name, p.prefix, ctx.global())
3417+
3418+
if !exists {
3419+
return nil, p.variableNotDefinedError(name, nameToken)
3420+
} else if namedValue.IsConstant() {
3421+
return nil, p.constantError(name, nameToken)
3422+
}
3423+
namedValueValueType := namedValue.ValueType()
3424+
baseTypeDefinition, exists := ctx.findType(namedValueValueType.DataType(), false)
3425+
3426+
if !exists {
3427+
return nil, p.atError(fmt.Sprintf(`type of %s could not be found`, name), nameToken)
3428+
}
3429+
baseValueType := baseTypeDefinition.valueType
3430+
3431+
if baseValueType.IsSlice() {
3432+
return nil, p.expectedError("struct but got slice", nameToken)
3433+
} else if baseValueType.DataType() != DATA_TYPE_STRUCT {
3434+
return nil, p.expectedError(fmt.Sprintf("struct but variable is of type %s", baseValueType.String()), nameToken)
3435+
}
3436+
structDeclaration, exists := ctx.findStruct(baseTypeDefinition.name)
3437+
3438+
if !exists {
3439+
return nil, p.atError(fmt.Sprintf(`declaration of struct %s could not be found`, name), nameToken)
3440+
}
3441+
nextToken := p.eat()
3442+
3443+
if nextToken.Type() != lexer.DOT {
3444+
return nil, p.expectedError(`"."`, nextToken)
3445+
}
3446+
nextToken = p.eat()
3447+
3448+
if nextToken.Type() != lexer.IDENTIFIER {
3449+
return nil, p.expectedError(`struct field`, nextToken)
3450+
}
3451+
structField, err := structDeclaration.FindField(nextToken.Value())
3452+
3453+
if err != nil {
3454+
return nil, p.atError(err.Error(), nextToken)
3455+
}
3456+
nextToken = p.eat()
3457+
3458+
if nextToken.Type() != lexer.ASSIGN_OPERATOR {
3459+
return nil, p.expectedError(`"="`, nameToken)
3460+
}
3461+
valueToken := p.peek()
3462+
value, err := p.evaluateExpression(ctx)
3463+
3464+
if err != nil {
3465+
return nil, err
3466+
}
3467+
variableValueType := structField.ValueType()
3468+
assignedValueType := value.ValueType()
3469+
3470+
if !variableValueType.Equals(assignedValueType) {
3471+
return nil, p.expectedError(fmt.Sprintf("%s value but got %s", variableValueType.String(), assignedValueType.String()), valueToken)
3472+
}
3473+
return StructAssignment{
3474+
Variable: namedValue.(Variable),
3475+
value: StructValue{
3476+
StructField: structField,
3477+
value: value,
3478+
},
3479+
}, nil
3480+
}
3481+
34003482
func (p *Parser) evaluateIncrementDecrement(ctx context) (Statement, error) {
34013483
identifierToken := p.eat()
34023484

0 commit comments

Comments
 (0)