Example Language Compiler for MUD - wwestlake/Labyrinth GitHub Wiki

Example Language Compiler for MUD

Explanation:

  1. Domain Model: Defines the basic elements like User, Room, Map, and Context.
  2. Command Types: Defines the possible commands that can be parsed and executed.
  3. Parsers: Uses FParsec to create parsers for the command language.
  4. Context Functions: Utility functions to access the context, like checking if an item is in the user’s inventory.
  5. Command Processor: A function that processes commands based on the context.
  6. Example Context: An example Context is provided to test the commands.
  7. Example Usage: Demonstrates how to parse and process commands.

This concept is a starting point and can be expanded to include more complex commands, error handling, and other MUD-specific logic.

open FParsec
open System

// Define the domain model
type User = { Name: string; Health: int; Inventory: string list }
type Room = { Name: string; Enemies: string list; Items: string list }
type Map = { Rooms: Room list }
type Context = { User: User; CurrentRoom: Room; Map: Map }

// Define the commands
type Command =
    | Attack of string
    | Take of string
    | Move of string
    | Say of string
    | If of (Context -> bool) * Command

// Basic parsers
let ws = spaces
let str_ws s = pstring s .>> ws
let identifier = many1Satisfy2L isLetter (isLetter <|> isDigit) "identifier" .>> ws

// Context functions
let getEnemy context enemyName =
    context.CurrentRoom.Enemies |> List.tryFind (fun enemy -> enemy = enemyName)

let userHasItem context itemName =
    context.User.Inventory |> List.contains itemName

// Command parsers
let attackParser =
    str_ws "attack" >>. identifier |>> Attack

let takeParser =
    str_ws "take" >>. identifier |>> Take

let moveParser =
    str_ws "move" >>. identifier |>> Move

let sayParser =
    str_ws "say" >>. many1Satisfy (fun c -> c <> '\n') |>> Say

// Conditional parser
let ifParser, ifParserRef = createParserForwardedToRef<Command, unit>()

let conditionParser =
    str_ws "if" >>. between (str_ws "(") (str_ws ")") identifier .>>. ifParser
    |>> (fun (cond, command) ->
        let conditionFunc context =
            match cond with
            | "lowHealth" -> context.User.Health < 20
            | item -> userHasItem context item
        If(conditionFunc, command))

do ifParserRef := choice [attackParser; takeParser; moveParser; sayParser]

// Command processor
let processCommand context (command: Command) =
    match command with
    | Attack enemy ->
        match getEnemy context enemy with
        | Some _ -> printfn "You attack the %s." enemy
        | None -> printfn "No enemy named %s found." enemy
    | Take item ->
        if userHasItem context item then
            printfn "You already have the %s." item
        else if List.contains item context.CurrentRoom.Items then
            printfn "You take the %s." item
        else
            printfn "No item named %s found." item
    | Move direction ->
        printfn "You move %s." direction
    | Say message ->
        printfn "%s says: %s" context.User.Name message
    | If(condition, command) ->
        if condition context then
            processCommand context command

// Example context
let exampleContext =
    {
        User = { Name = "Hero"; Health = 15; Inventory = ["sword"; "shield"] }
        CurrentRoom = { Name = "Dungeon"; Enemies = ["goblin"; "orc"]; Items = ["potion"; "key"] }
        Map = { Rooms = [] }
    }

// Example usage
let runExampleCommand input =
    match run (ws >>. ifParser) input with
    | Success(result, _, _) -> processCommand exampleContext result
    | Failure(errorMsg, _, _) -> printfn "Error: %s" errorMsg

// Test the parser and processor
runExampleCommand "attack goblin"
runExampleCommand "take potion"
runExampleCommand "say Hello, world!"
runExampleCommand "if (lowHealth) say I'm low on health!"
⚠️ **GitHub.com Fallback** ⚠️