modelica.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. // Modelica support for CodeMirror, copyright (c) by Lennart Ochel
  4. ;(function (mod) {
  5. if (typeof exports == 'object' && typeof module == 'object')
  6. // CommonJS
  7. mod(require('../../lib/codemirror'))
  8. else if (typeof define == 'function' && define.amd)
  9. // AMD
  10. define(['../../lib/codemirror'], mod)
  11. // Plain browser env
  12. else mod(CodeMirror)
  13. })(function (CodeMirror) {
  14. 'use strict'
  15. CodeMirror.defineMode('modelica', function (config, parserConfig) {
  16. var indentUnit = config.indentUnit
  17. var keywords = parserConfig.keywords || {}
  18. var builtin = parserConfig.builtin || {}
  19. var atoms = parserConfig.atoms || {}
  20. var isSingleOperatorChar = /[;=\(:\),{}.*<>+\-\/^\[\]]/
  21. var isDoubleOperatorChar = /(:=|<=|>=|==|<>|\.\+|\.\-|\.\*|\.\/|\.\^)/
  22. var isDigit = /[0-9]/
  23. var isNonDigit = /[_a-zA-Z]/
  24. function tokenLineComment(stream, state) {
  25. stream.skipToEnd()
  26. state.tokenize = null
  27. return 'comment'
  28. }
  29. function tokenBlockComment(stream, state) {
  30. var maybeEnd = false,
  31. ch
  32. while ((ch = stream.next())) {
  33. if (maybeEnd && ch == '/') {
  34. state.tokenize = null
  35. break
  36. }
  37. maybeEnd = ch == '*'
  38. }
  39. return 'comment'
  40. }
  41. function tokenString(stream, state) {
  42. var escaped = false,
  43. ch
  44. while ((ch = stream.next()) != null) {
  45. if (ch == '"' && !escaped) {
  46. state.tokenize = null
  47. state.sol = false
  48. break
  49. }
  50. escaped = !escaped && ch == '\\'
  51. }
  52. return 'string'
  53. }
  54. function tokenIdent(stream, state) {
  55. stream.eatWhile(isDigit)
  56. while (stream.eat(isDigit) || stream.eat(isNonDigit)) {}
  57. var cur = stream.current()
  58. if (state.sol && (cur == 'package' || cur == 'model' || cur == 'when' || cur == 'connector')) state.level++
  59. else if (state.sol && cur == 'end' && state.level > 0) state.level--
  60. state.tokenize = null
  61. state.sol = false
  62. if (keywords.propertyIsEnumerable(cur)) return 'keyword'
  63. else if (builtin.propertyIsEnumerable(cur)) return 'builtin'
  64. else if (atoms.propertyIsEnumerable(cur)) return 'atom'
  65. else return 'variable'
  66. }
  67. function tokenQIdent(stream, state) {
  68. while (stream.eat(/[^']/)) {}
  69. state.tokenize = null
  70. state.sol = false
  71. if (stream.eat("'")) return 'variable'
  72. else return 'error'
  73. }
  74. function tokenUnsignedNumber(stream, state) {
  75. stream.eatWhile(isDigit)
  76. if (stream.eat('.')) {
  77. stream.eatWhile(isDigit)
  78. }
  79. if (stream.eat('e') || stream.eat('E')) {
  80. if (!stream.eat('-')) stream.eat('+')
  81. stream.eatWhile(isDigit)
  82. }
  83. state.tokenize = null
  84. state.sol = false
  85. return 'number'
  86. }
  87. // Interface
  88. return {
  89. startState: function () {
  90. return {
  91. tokenize: null,
  92. level: 0,
  93. sol: true,
  94. }
  95. },
  96. token: function (stream, state) {
  97. if (state.tokenize != null) {
  98. return state.tokenize(stream, state)
  99. }
  100. if (stream.sol()) {
  101. state.sol = true
  102. }
  103. // WHITESPACE
  104. if (stream.eatSpace()) {
  105. state.tokenize = null
  106. return null
  107. }
  108. var ch = stream.next()
  109. // LINECOMMENT
  110. if (ch == '/' && stream.eat('/')) {
  111. state.tokenize = tokenLineComment
  112. }
  113. // BLOCKCOMMENT
  114. else if (ch == '/' && stream.eat('*')) {
  115. state.tokenize = tokenBlockComment
  116. }
  117. // TWO SYMBOL TOKENS
  118. else if (isDoubleOperatorChar.test(ch + stream.peek())) {
  119. stream.next()
  120. state.tokenize = null
  121. return 'operator'
  122. }
  123. // SINGLE SYMBOL TOKENS
  124. else if (isSingleOperatorChar.test(ch)) {
  125. state.tokenize = null
  126. return 'operator'
  127. }
  128. // IDENT
  129. else if (isNonDigit.test(ch)) {
  130. state.tokenize = tokenIdent
  131. }
  132. // Q-IDENT
  133. else if (ch == "'" && stream.peek() && stream.peek() != "'") {
  134. state.tokenize = tokenQIdent
  135. }
  136. // STRING
  137. else if (ch == '"') {
  138. state.tokenize = tokenString
  139. }
  140. // UNSIGNED_NUMBER
  141. else if (isDigit.test(ch)) {
  142. state.tokenize = tokenUnsignedNumber
  143. }
  144. // ERROR
  145. else {
  146. state.tokenize = null
  147. return 'error'
  148. }
  149. return state.tokenize(stream, state)
  150. },
  151. indent: function (state, textAfter) {
  152. if (state.tokenize != null) return CodeMirror.Pass
  153. var level = state.level
  154. if (/(algorithm)/.test(textAfter)) level--
  155. if (/(equation)/.test(textAfter)) level--
  156. if (/(initial algorithm)/.test(textAfter)) level--
  157. if (/(initial equation)/.test(textAfter)) level--
  158. if (/(end)/.test(textAfter)) level--
  159. if (level > 0) return indentUnit * level
  160. else return 0
  161. },
  162. blockCommentStart: '/*',
  163. blockCommentEnd: '*/',
  164. lineComment: '//',
  165. }
  166. })
  167. function words(str) {
  168. var obj = {},
  169. words = str.split(' ')
  170. for (var i = 0; i < words.length; ++i) obj[words[i]] = true
  171. return obj
  172. }
  173. var modelicaKeywords =
  174. 'algorithm and annotation assert block break class connect connector constant constrainedby der discrete each else elseif elsewhen encapsulated end enumeration equation expandable extends external false final flow for function if import impure in initial inner input loop model not operator or outer output package parameter partial protected public pure record redeclare replaceable return stream then true type when while within'
  175. var modelicaBuiltin =
  176. 'abs acos actualStream asin atan atan2 cardinality ceil cos cosh delay div edge exp floor getInstanceName homotopy inStream integer log log10 mod pre reinit rem semiLinear sign sin sinh spatialDistribution sqrt tan tanh'
  177. var modelicaAtoms = 'Real Boolean Integer String'
  178. function def(mimes, mode) {
  179. if (typeof mimes == 'string') mimes = [mimes]
  180. var words = []
  181. function add(obj) {
  182. if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) words.push(prop)
  183. }
  184. add(mode.keywords)
  185. add(mode.builtin)
  186. add(mode.atoms)
  187. if (words.length) {
  188. mode.helperType = mimes[0]
  189. CodeMirror.registerHelper('hintWords', mimes[0], words)
  190. }
  191. for (var i = 0; i < mimes.length; ++i) CodeMirror.defineMIME(mimes[i], mode)
  192. }
  193. def(['text/x-modelica'], {
  194. name: 'modelica',
  195. keywords: words(modelicaKeywords),
  196. builtin: words(modelicaBuiltin),
  197. atoms: words(modelicaAtoms),
  198. })
  199. })