diff --git a/ast/ast.go b/ast/ast.go index 634f647..722e8d7 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -491,13 +491,14 @@ func (se *SliceExpr) TokenLiteral() string { return se.Token.Literal } // Abbreviation represents an abbreviation: VAL INT x IS 42:, INT y IS z:, or INITIAL INT x IS 42: type Abbreviation struct { - Token lexer.Token // VAL, INITIAL, or type token - IsVal bool // true for VAL abbreviations - IsInitial bool // true for INITIAL declarations - IsOpenArray bool // true for []TYPE abbreviations (e.g. VAL []BYTE) - Type string // "INT", "BYTE", "BOOL", etc. - Name string // variable name - Value Expression // the expression + Token lexer.Token // VAL, INITIAL, or type token + IsVal bool // true for VAL abbreviations + IsInitial bool // true for INITIAL declarations + IsOpenArray bool // true for []TYPE abbreviations (e.g. VAL []BYTE) + IsFixedArray bool // true for [n]TYPE abbreviations (e.g. VAL [8]INT) + Type string // "INT", "BYTE", "BOOL", etc. + Name string // variable name + Value Expression // the expression } func (a *Abbreviation) statementNode() {} diff --git a/codegen/codegen.go b/codegen/codegen.go index 8d6e4c8..4211f74 100644 --- a/codegen/codegen.go +++ b/codegen/codegen.go @@ -35,6 +35,9 @@ type Generator struct { recordDefs map[string]*ast.RecordDecl recordVars map[string]string // variable name → record type name + // Channel element type tracking (for ALT guard codegen) + chanElemTypes map[string]string // channel name → Go element type + // Bool variable tracking (for type conversion codegen) boolVars map[string]bool @@ -106,6 +109,7 @@ func (g *Generator) Generate(program *ast.Program) string { g.refParams = make(map[string]bool) g.protocolDefs = make(map[string]*ast.ProtocolDecl) g.chanProtocols = make(map[string]string) + g.chanElemTypes = make(map[string]string) g.tmpCounter = 0 g.recordDefs = make(map[string]*ast.RecordDecl) g.recordVars = make(map[string]string) @@ -279,7 +283,7 @@ func (g *Generator) Generate(program *ast.Program) string { g.write("\n") } else { goType := g.occamTypeToGo(abbr.Type) - if abbr.IsOpenArray { + if abbr.IsOpenArray || abbr.IsFixedArray { goType = "[]" + goType } g.builder.WriteString("var ") @@ -1108,7 +1112,7 @@ func (g *Generator) generateAbbreviation(abbr *ast.Abbreviation) { g.builder.WriteString(strings.Repeat("\t", g.indent)) if abbr.Type != "" { goType := g.occamTypeToGo(abbr.Type) - if abbr.IsOpenArray { + if abbr.IsOpenArray || abbr.IsFixedArray { goType = "[]" + goType } g.write(fmt.Sprintf("var %s %s = ", goIdent(abbr.Name), goType)) @@ -1132,6 +1136,9 @@ func (g *Generator) generateAbbreviation(abbr *ast.Abbreviation) { func (g *Generator) generateChanDecl(decl *ast.ChanDecl) { goType := g.occamTypeToGo(decl.ElemType) + for _, name := range decl.Names { + g.chanElemTypes[name] = goType + } if len(decl.Sizes) > 0 { for _, name := range decl.Names { n := goIdent(name) @@ -1884,11 +1891,12 @@ func (g *Generator) generateAltBlock(alt *ast.AltBlock) { for i, c := range alt.Cases { if c.Guard != nil && !c.IsSkip { g.builder.WriteString(strings.Repeat("\t", g.indent)) - g.write(fmt.Sprintf("var _alt%d chan ", i)) - // We don't know the channel type here, so use interface{} - // Actually, we should use the same type as the original channel - // For now, let's just reference the original channel conditionally - g.write(fmt.Sprintf("int = nil\n")) // Assuming int for now + // Look up the channel's element type + elemType := "int" // default fallback + if t, ok := g.chanElemTypes[c.Channel]; ok { + elemType = t + } + g.write(fmt.Sprintf("var _alt%d <-chan %s = nil\n", i, elemType)) g.builder.WriteString(strings.Repeat("\t", g.indent)) g.write(fmt.Sprintf("if ")) g.generateExpression(c.Guard) @@ -2100,11 +2108,12 @@ func (g *Generator) generateProcDecl(proc *ast.ProcDecl) { } else { delete(newBoolVars, p.Name) } - // Register chan params with protocol mappings + // Register chan params with protocol mappings and element types if p.IsChan || p.ChanArrayDims > 0 { if _, ok := g.protocolDefs[p.ChanElemType]; ok { g.chanProtocols[p.Name] = p.ChanElemType } + g.chanElemTypes[p.Name] = g.occamTypeToGo(p.ChanElemType) } // Register record-typed params if !p.IsChan { diff --git a/historical-examples/life.occ b/historical-examples/life.occ index d3997bf..69b738b 100644 --- a/historical-examples/life.occ +++ b/historical-examples/life.occ @@ -4,6 +4,35 @@ -- -- The program in this chapter plays Life on a terminal screen. -- +-- Adapted for occam2go: replaced book-library functions +-- (write.string, write.formatted, DATA.ITEM) with inline +-- definitions; added terminal.keyboard/terminal.screen declarations. +-- + +-- +-- helper procedures (replaces book standard library) +-- + +PROC write.string(CHAN OF BYTE out!, VAL []BYTE s) + SEQ i = 0 FOR SIZE s + out ! s[i] +: + +PROC write.small.int(CHAN OF BYTE out!, VAL INT n) + -- outputs a small non-negative integer (0..999) as decimal digits + IF + n >= 100 + SEQ + out ! BYTE ((n / 100) + (INT '0')) + out ! BYTE (((n / 10) \ 10) + (INT '0')) + out ! BYTE ((n \ 10) + (INT '0')) + n >= 10 + SEQ + out ! BYTE ((n / 10) + (INT '0')) + out ! BYTE ((n \ 10) + (INT '0')) + TRUE + out ! BYTE (n + (INT '0')) +: -- -- configuration constants @@ -120,19 +149,25 @@ PROC cell([][][]CHAN OF STATE link, -- terminal-dependent output routines -- -PROC clear.screen(CHAN OF BYTE terminal) - -- clear screen sequence for an ANSI terminal - write.string(terminal, "*#1B[2J") +PROC clear.screen(CHAN OF BYTE terminal!) + -- clear screen sequence for an ANSI terminal: ESC [ 2 J + SEQ + terminal ! BYTE #1B + terminal ! '[' + terminal ! '2' + terminal ! 'J' : -PROC move.cursor(CHAN OF BYTE terminal, VAL INT x, y) +PROC move.cursor(CHAN OF BYTE terminal!, VAL INT x, y) -- left-handed co-ordinates, origin 0,0 at top left - CHAN OF DATA.ITEM c : - PAR - write.formatted(terminal, "*#1B[%d;%dH", c) - SEQ - c ! data.int; y + 1 - c ! data.int; x + 1 + -- outputs ANSI escape sequence: ESC [ row ; col H + SEQ + terminal ! BYTE #1B + terminal ! '[' + write.small.int(terminal, y + 1) + terminal ! ';' + write.small.int(terminal, x + 1) + terminal ! 'H' : @@ -142,16 +177,16 @@ PROC move.cursor(CHAN OF BYTE terminal, VAL INT x, y) -- display routines -- -PROC initialize.display(CHAN OF BYTE screen) +PROC initialize.display(CHAN OF BYTE screen!) -- display an entirely dead board clear.screen(screen) : -PROC clean.up.display(CHAN OF BYTE screen) +PROC clean.up.display(CHAN OF BYTE screen!) move.cursor(screen, 0, array.height) : -PROC display.state(CHAN OF BYTE screen, VAL INT x, y, VAL BOOL state) +PROC display.state(CHAN OF BYTE screen!, VAL INT x, y, VAL BOOL state) SEQ move.cursor(screen, x, y) IF @@ -189,7 +224,7 @@ INT FUNCTION new.activity(VAL BYTE char) RESULT activity : -PROC display.activity(CHAN OF BYTE screen, VAL INT activity) +PROC display.activity(CHAN OF BYTE screen!, VAL INT activity) SEQ move.cursor(screen, array.width+1, array.height/2) CASE activity @@ -209,7 +244,7 @@ PROC display.activity(CHAN OF BYTE screen, VAL INT activity) -- generation -- -PROC generation(CHAN OF BYTE screen, +PROC generation(CHAN OF BYTE screen!, [][]CHAN OF COMMAND control, [][]CHAN OF RESPONSE sense, BOOL active ) @@ -291,7 +326,7 @@ INT FUNCTION max(VAL INT a, b) -PROC editor(CHAN OF BYTE keyboard, screen, +PROC editor(CHAN OF BYTE keyboard?, screen!, [][]CHAN OF COMMAND control ) INT x, y : BOOL editing : @@ -346,7 +381,7 @@ PROC editor(CHAN OF BYTE keyboard, screen, -- controller -- -PROC controller(CHAN OF BYTE keyboard, screen, +PROC controller(CHAN OF BYTE keyboard?, screen!, [][]CHAN OF COMMAND control, [][]CHAN OF RESPONSE sense ) INT activity : @@ -397,20 +432,22 @@ PROC controller(CHAN OF BYTE keyboard, screen, -- structure of the program -- -[array.width][array.height][neighbours]CHAN OF STATE link : -[array.width][array.height]CHAN OF COMMAND control : -[array.width][array.height]CHAN OF RESPONSE sense : -PAR - controller(terminal.keyboard, terminal.screen, control, sense) - PAR x = 0 FOR array.width - PAR y = 0 FOR array.height - VAL INT left IS ((x - 1) + array.width) \ array.width : - VAL INT right IS (x + 1) \ array.width : - VAL INT up IS (y + 1) \ array.height : - VAL INT down IS ((y - 1) + array.height) \ array.height : - VAL [neighbours]INT nx IS - [ right, x, left, left, left, x, right, right ] : - VAL [neighbours]INT ny IS - [ down, down, down, y, up, up, up, y ] : - cell(link, x, y, nx, ny, control[x][y], sense[x][y]) +PROC life (CHAN BYTE keyboard?, screen!, error!) + [array.width][array.height][neighbours]CHAN OF STATE link : + [array.width][array.height]CHAN OF COMMAND control : + [array.width][array.height]CHAN OF RESPONSE sense : + PAR + controller(keyboard, screen, control, sense) + PAR x = 0 FOR array.width + PAR y = 0 FOR array.height + VAL INT left IS ((x - 1) + array.width) \ array.width : + VAL INT right IS (x + 1) \ array.width : + VAL INT up IS (y + 1) \ array.height : + VAL INT down IS ((y - 1) + array.height) \ array.height : + VAL [neighbours]INT nx IS + [ right, x, left, left, left, x, right, right ] : + VAL [neighbours]INT ny IS + [ down, down, down, y, up, up, up, y ] : + cell(link, x, y, nx, ny, control[x][y], sense[x][y]) +: diff --git a/parser/parser.go b/parser/parser.go index 9e90386..2ec9d5f 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -417,12 +417,13 @@ func (p *Parser) parseAbbreviation() ast.Statement { } return &ast.Abbreviation{ - Token: token, - IsVal: true, - IsOpenArray: isOpenArray, - Type: typeName, - Name: name, - Value: value, + Token: token, + IsVal: true, + IsOpenArray: isOpenArray, + IsFixedArray: isArray, + Type: typeName, + Name: name, + Value: value, } }