Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
53 changes: 45 additions & 8 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 @@ -121,18 +150,24 @@ PROC cell([][][]CHAN OF STATE link,
--

PROC clear.screen(CHAN OF BYTE terminal)
-- clear screen sequence for an ANSI terminal
write.string(terminal, "*#1B[2J")
-- 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)
-- 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 Down Expand Up @@ -397,6 +432,8 @@ PROC controller(CHAN OF BYTE keyboard, screen,
-- structure of the program
--

CHAN OF BYTE terminal.keyboard :
CHAN OF BYTE terminal.screen :
[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 :
Expand Down
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