Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Expand Down
25 changes: 17 additions & 8 deletions codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 ")
Expand Down Expand Up @@ -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))
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down
103 changes: 70 additions & 33 deletions historical-examples/life.occ
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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'
:


Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 )
Expand Down Expand Up @@ -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 :
Expand Down Expand Up @@ -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 :
Expand Down Expand Up @@ -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])
:

13 changes: 7 additions & 6 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}

Expand Down
Loading