Skip to content

Instantly share code, notes, and snippets.

@itsMapleLeaf
Last active June 1, 2016 02:48
Show Gist options
  • Save itsMapleLeaf/f4ff3d265bb615ef430ba906b4f3c64d to your computer and use it in GitHub Desktop.
Save itsMapleLeaf/f4ff3d265bb615ef430ba906b4f3c64d to your computer and use it in GitHub Desktop.
module lexer


interface LexerState
  source: string
  current: number
  tokens: Token[]

interface Token
  type: string
  value: string


init source (LexerState, string -> LexerState) :=
  { self | source = source, current = 1, tokens = {} }

match pattern tokentype (LexerState, string, string -> LexerState, boolean) :=
  let
    position, value = self.source:match ('()(' .. pattern .. ')') self.current
  in
    if position == self.current then
      let
        token = { type = 'tokentype', value = value }
      in
        { self |
          current = self.current + 1,
          tokens = self.tokens :: token,
        }, true
    else
      self, false

lex done (LexerState, boolean? -> Token[]?, string?) :=
  if not done then
    let
      self, success = self:match '[%a_][%w_]' 'name'
        or self:match '%d*%.?%d+' 'number'
        or self:match '%=' 'equals'
        or self:match '%+' 'plus'
        or self:match '%s+'
    in
      if success then
        self:lex self.current <= #self.tokens
      else
        let
          errformat = "unexpected character '%s'"
          errmsg = errformat:format (self.source:sub self.current self.current)
        in
          nil, errmsg
  else
    self.tokens, nil

new ... (...any -> LexerState) =
  let
    self = setmetatable {} { __index = lexer }
  in
    init self ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment