├── lib ├── duktape │ └── version.rb └── duktape.rb ├── .gitignore ├── .travis.yml ├── ext └── duktape │ ├── extconf.rb │ ├── duktape_ext.c │ └── duktape.h ├── MANIFEST.txt ├── Gemfile ├── duktape.gemspec ├── example.rb ├── CHANGELOG.md ├── Rakefile ├── README.md └── test └── test_duktape.rb /lib/duktape/version.rb: -------------------------------------------------------------------------------- 1 | module Duktape 2 | VERSION = "1.3.0.5" 3 | end 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bundle 2 | *.gem 3 | /.bundle 4 | /pkg 5 | /Gemfile.lock 6 | /tmp 7 | /docs 8 | -------------------------------------------------------------------------------- /lib/duktape.rb: -------------------------------------------------------------------------------- 1 | require 'duktape_ext' 2 | require 'duktape/version' 3 | 4 | module Duktape 5 | end 6 | 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | sudo: false 3 | cache: bundler 4 | rvm: 5 | - 1.9.3 6 | - 2.0.0 7 | - 2.1.8 8 | - 2.2.4 9 | - 2.3.0 10 | -------------------------------------------------------------------------------- /ext/duktape/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | require 'zlib' 3 | 4 | $CFLAGS += ' -std=c99' 5 | have_func 'rb_sym2str' 6 | create_makefile 'duktape_ext' 7 | 8 | -------------------------------------------------------------------------------- /MANIFEST.txt: -------------------------------------------------------------------------------- 1 | README.md 2 | CHANGELOG.md 3 | ext/duktape/duktape.c 4 | ext/duktape/duktape.h 5 | ext/duktape/duktape_ext.c 6 | ext/duktape/duk_config.h 7 | ext/duktape/extconf.rb 8 | lib/duktape/version.rb 9 | lib/duktape.rb 10 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | gem 'rake' 6 | gem 'rake-compiler' 7 | gem 'sdoc' 8 | 9 | group :development do 10 | gem 'aws-sdk', '2.2.1' 11 | gem 'fatgem' 12 | end 13 | 14 | group :test do 15 | gem 'minitest', '~> 5.2' 16 | end 17 | 18 | -------------------------------------------------------------------------------- /duktape.gemspec: -------------------------------------------------------------------------------- 1 | require File.expand_path("../lib/duktape/version", __FILE__) 2 | 3 | Gem::Specification.new do |s| 4 | s.name = "duktape" 5 | s.version = Duktape::VERSION 6 | s.summary = "Bindings to the Duktape JavaScript interpreter" 7 | 8 | s.author = "Magnus Holm" 9 | s.email = "judofyr@gmail.com" 10 | s.homepage = "https://github.com/judofyr/duktape.rb" 11 | s.license = "MIT" 12 | 13 | s.files = File.readlines('MANIFEST.txt').map(&:strip) 14 | s.extensions = "ext/duktape/extconf.rb" 15 | 16 | s.required_ruby_version = ">= 1.9.3" 17 | end 18 | -------------------------------------------------------------------------------- /example.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH << 'lib' << 'ext/duktape' 2 | require 'duktape' 3 | 4 | # Create a new context 5 | ctx = Duktape::Context.new 6 | 7 | ## Evaluate a string 8 | p ctx.eval_string('1 + 1', 'hello.js') # => 2 9 | 10 | ## Safely evaluate a string 11 | ctx.eval_string < :compile do 34 | ruby 'test/test_duktape.rb' 35 | end 36 | 37 | task :default => :test 38 | 39 | task :upload do 40 | require 'aws-sdk' 41 | s3 = Aws::S3::Resource.new 42 | bucket = s3.bucket('holmium') 43 | prefix = "duktape-gem/" 44 | commit = `git rev-parse HEAD`.strip 45 | version = RUBY_VERSION.split(".")[0,2].join(".") 46 | 47 | Dir.glob("pkg/*.gem") do |filename| 48 | path = File.expand_path(filename) 49 | target = File.basename(filename) 50 | target = target.sub(/\.gem/, ".ruby#{version}.sha#{commit}.gem") 51 | object = bucket.object(prefix + target) 52 | object.upload_file(path, :acl => "public-read") 53 | puts "Gem available at #{object.public_url}" 54 | end 55 | end 56 | 57 | task :fatlinux => :build do |t, args| 58 | platform = "x86_64-linux" 59 | commit = `git rev-parse HEAD`.strip 60 | version = Duktape::VERSION 61 | 62 | paths = ["pkg/duktape-#{version}.gem"] 63 | 64 | %w[1.9 2.0 2.1 2.2 2.3].each do |ruby_version| 65 | paths << "https://holmium.s3-eu-west-1.amazonaws.com/duktape-gem/duktape-#{version}-#{platform}.ruby#{ruby_version}.sha#{commit}.gem" 66 | end 67 | 68 | sh "fatgem", *paths 69 | end 70 | 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Duktape.rb 2 | 3 | Duktape.rb is a C extension for the [Duktape](http://duktape.org/) JavaScript 4 | interpreter. 5 | 6 | ## Quickstart 7 | 8 | ```sh 9 | $ rake 10 | $ ruby example.rb 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```ruby 16 | require 'duktape' 17 | 18 | # Create a new context 19 | ctx = Duktape::Context.new 20 | 21 | ## Evaluate a string 22 | p ctx.eval_string('1 + 1') # => 2 23 | ``` 24 | 25 | ### Contexts 26 | 27 | Creating a context creates a fresh evaluation environment with no global 28 | variables or functions defined. 29 | 30 | A common pattern is to create a new context, define static functions once, and 31 | reuse the context to invoke the function many times with `call_prop`. 32 | 33 | ``` ruby 34 | ctx = Duktape::Context.new 35 | 36 | ctx.exec_string <<-JS 37 | function process(str, options) { 38 | // ... 39 | } 40 | JS 41 | 42 | ctx.call_prop('process', 'some data', a: 1, b: 2) 43 | ``` 44 | 45 | ### Call APIs 46 | 47 | * `exec_string` - Evaluate a JavaScript String on the context and return `nil`. 48 | * `eval_string` - Evaluate a JavaScript String expression and return the result 49 | as a Ruby Object. 50 | - `get_prop` - Access the property of the global object and return the value 51 | as a Ruby Object. 52 | - `call_prop` - Call a defined function with the given parameters and return 53 | the value as a Ruby Object. 54 | 55 | ### Exceptions 56 | 57 | Executing JS may raise two classes of errors: `Duktape::Error` and 58 | `Duktape::InternalError`. 59 | 60 | Any JS runtime error that is thrown in the interpreter is converted to a Ruby 61 | `Duktape::Error`. Specific error subclasses, such as `SyntaxError` and 62 | `TypeError`, are mapped from JS to the Ruby equivalent of the same name. 63 | 64 | ``` ruby 65 | ctx = Duktape::Context.new 66 | ctx.exec_string < 1, "b" => 2 }, @ctx.eval_string('({a: 1, b: 2})')) 72 | assert_equal({ "a" => 1, "b" => [2] }, @ctx.eval_string('({a: 1, b: [2]})')) 73 | assert_equal({ "a" => 1, "b" => { "c" => 2 } }, @ctx.eval_string('({a: 1, b: {c: 2}})')) 74 | end 75 | 76 | def test_complex_object 77 | assert_equal Duktape::ComplexObject.instance, 78 | @ctx.eval_string('a = function() {}') 79 | end 80 | 81 | def test_throw_error 82 | err = assert_raises(Duktape::Error) do 83 | @ctx.eval_string('throw new Error("boom")') 84 | end 85 | 86 | assert_equal "boom", err.message 87 | end 88 | 89 | def test_reference_error 90 | err = assert_raises(Duktape::ReferenceError) do 91 | @ctx.eval_string('fail') 92 | end 93 | 94 | assert_equal "identifier 'fail' undefined", err.message 95 | end 96 | 97 | def test_syntax_error 98 | err = assert_raises(Duktape::SyntaxError) do 99 | @ctx.eval_string('{') 100 | end 101 | 102 | assert_equal "parse error (line 1)", err.message 103 | end 104 | 105 | def test_type_error 106 | err = assert_raises(Duktape::TypeError) do 107 | @ctx.eval_string('null.fail') 108 | end 109 | 110 | assert_equal "invalid base value", err.message 111 | end 112 | 113 | def test_error_message_not_garbage_collected 114 | 1000.times do 115 | err = assert_raises(Duktape::ReferenceError) do 116 | @ctx.eval_string('fail') 117 | end 118 | assert_equal "identifier 'fail' undefined", err.message 119 | end 120 | end 121 | end 122 | 123 | describe "#exec_string" do 124 | def test_with_filename 125 | @ctx.exec_string('a = 1', __FILE__) 126 | assert_equal 1.0, @ctx.eval_string('a', __FILE__) 127 | end 128 | 129 | def test_basic 130 | @ctx.exec_string('a = 1') 131 | assert_equal 1.0, @ctx.eval_string('a') 132 | end 133 | 134 | def test_doesnt_try_convert 135 | @ctx.exec_string('a = {b:1}') 136 | assert_equal 1.0, @ctx.eval_string('a.b') 137 | end 138 | 139 | def test_throw_error 140 | err = assert_raises(Duktape::Error) do 141 | @ctx.exec_string('throw new Error("boom")') 142 | end 143 | 144 | assert_equal "boom", err.message 145 | end 146 | 147 | def test_reference_error 148 | err = assert_raises(Duktape::ReferenceError) do 149 | @ctx.exec_string('fail') 150 | end 151 | 152 | assert_equal "identifier 'fail' undefined", err.message 153 | end 154 | 155 | def test_syntax_error 156 | err = assert_raises(Duktape::SyntaxError) do 157 | @ctx.exec_string('{') 158 | end 159 | 160 | assert_equal "parse error (line 1)", err.message 161 | end 162 | 163 | def test_type_error 164 | err = assert_raises(Duktape::TypeError) do 165 | @ctx.exec_string('null.fail') 166 | end 167 | 168 | assert_equal 'invalid base value', err.message 169 | end 170 | end 171 | 172 | describe "#get_prop" do 173 | def test_basic 174 | @ctx.eval_string('a = 1') 175 | assert_equal 1.0, @ctx.get_prop('a') 176 | end 177 | 178 | def test_nested 179 | @ctx.eval_string('a = {}; a.b = {}; a.b.c = 1') 180 | assert_equal 1.0, @ctx.get_prop(['a', 'b', 'c']) 181 | end 182 | 183 | def test_nested_undefined 184 | @ctx.eval_string('a = {}') 185 | assert_equal nil, @ctx.get_prop(['a', 'missing']) 186 | end 187 | 188 | def test_missing 189 | err = assert_raises(Duktape::ReferenceError) do 190 | @ctx.get_prop('a') 191 | end 192 | 193 | assert_equal "identifier 'a' undefined", err.message 194 | end 195 | 196 | def test_nested_reference_error 197 | err = assert_raises(Duktape::ReferenceError) do 198 | @ctx.get_prop(['a', 'b']) 199 | end 200 | 201 | assert_equal "identifier 'a' undefined", err.message 202 | end 203 | 204 | def test_nested_type_error 205 | @ctx.eval_string('a = {};') 206 | 207 | err = assert_raises(Duktape::TypeError) do 208 | @ctx.get_prop(['a', 'b', 'c']) 209 | end 210 | 211 | assert_equal 'invalid base value', err.message 212 | end 213 | end 214 | 215 | describe "#call_prop" do 216 | before do 217 | @ctx.eval_string('function id(a) { return a }') 218 | end 219 | 220 | def test_str 221 | assert_equal 'Hei', @ctx.call_prop('id', 'Hei') 222 | end 223 | 224 | def test_symbols 225 | assert_equal "hello", @ctx.call_prop('id', :hello) 226 | end 227 | 228 | def test_fixnum 229 | assert_equal 2.0, @ctx.call_prop('id', 2) 230 | end 231 | 232 | def test_float 233 | assert_equal 2.0, @ctx.call_prop('id', 2.0) 234 | end 235 | 236 | def test_true 237 | assert_equal true, @ctx.call_prop('id', true) 238 | end 239 | 240 | def test_false 241 | assert_equal false, @ctx.call_prop('id', false) 242 | end 243 | 244 | def test_nil 245 | assert_equal nil, @ctx.call_prop('id', nil) 246 | end 247 | 248 | def test_arrays 249 | assert_equal [1.0], @ctx.call_prop('id', [1]) 250 | assert_equal [['foo', [1.0]]], @ctx.call_prop('id', [['foo', [1]]]) 251 | end 252 | 253 | def test_hashes 254 | assert_equal({'hello' => 123}, @ctx.call_prop('id', {'hello' => 123})) 255 | assert_equal({'hello' => [{'foo' => 123}]}, @ctx.call_prop('id', {'hello' => [{'foo' => 123}]})) 256 | end 257 | 258 | def test_hashes_with_symbol_key 259 | assert_equal({'hello' => 123}, @ctx.call_prop('id', {:hello => 123})) 260 | end 261 | 262 | def test_hashes_with_complex_entries 263 | assert_raises TypeError do 264 | @ctx.call_prop('id', {:hello => Object.new}) 265 | end 266 | 267 | assert_raises TypeError do 268 | @ctx.call_prop('id', {123 => "hello"}) 269 | end 270 | end 271 | 272 | def test_hashes_with_complex_values 273 | res = @ctx.eval_string('({a:1,b:function(){}})') 274 | assert_equal({'a' => 1}, res) 275 | end 276 | 277 | def test_objects_with_prototypes 278 | res = @ctx.eval_string <<-JS 279 | function A() { 280 | this.value = 123; 281 | this.fn = function() {}; 282 | } 283 | A.prototype.b = 456; 284 | A.prototype.c = function() {}; 285 | new A; 286 | JS 287 | 288 | assert_equal({'value' => 123}, res) 289 | end 290 | 291 | def test_binding 292 | @ctx.eval_string <<-JS 293 | var self = this 294 | function test() { return this === self } 295 | JS 296 | assert_equal true, @ctx.call_prop('test') 297 | end 298 | 299 | def test_nested_property 300 | @ctx.eval_string <<-JS 301 | a = {} 302 | a.b = {} 303 | a.b.id = function(v) { return v; } 304 | JS 305 | assert_equal 'Hei', @ctx.call_prop(['a', 'b', 'id'], 'Hei') 306 | end 307 | 308 | def test_nested_binding 309 | @ctx.eval_string <<-JS 310 | a = {} 311 | a.b = {} 312 | a.b.test = function() { return this == a.b; } 313 | JS 314 | assert_equal true, @ctx.call_prop(['a', 'b', 'test']) 315 | end 316 | 317 | def test_throw_error 318 | @ctx.eval_string('function fail(msg) { throw new Error(msg) }') 319 | 320 | err = assert_raises(Duktape::Error) do 321 | @ctx.call_prop('fail', 'boom') 322 | end 323 | 324 | assert_equal "boom", err.message 325 | end 326 | 327 | def test_reference_error 328 | err = assert_raises(Duktape::ReferenceError) do 329 | @ctx.call_prop('missing') 330 | end 331 | 332 | assert_equal "identifier 'missing' undefined", err.message 333 | end 334 | 335 | def test_nested_reference_error 336 | err = assert_raises(Duktape::ReferenceError) do 337 | @ctx.call_prop(['missing', 'foo']) 338 | end 339 | 340 | assert_equal "identifier 'missing' undefined", err.message 341 | end 342 | 343 | def test_nested_type_error 344 | @ctx.eval_string 'a = {}' 345 | 346 | err = assert_raises(Duktape::TypeError) do 347 | @ctx.call_prop(['a', 'missing']) 348 | end 349 | 350 | assert_equal 'not callable', err.message 351 | end 352 | 353 | def test_unknown_argument_type 354 | err = assert_raises(TypeError) do 355 | @ctx.call_prop('id', Object.new) 356 | end 357 | assert_match /Object/, err.message 358 | 359 | assert_raises(TypeError) do 360 | @ctx.call_prop('id', [Object.new]) 361 | end 362 | 363 | assert_raises(TypeError) do 364 | @ctx.call_prop('id', {123 => Object.new}) 365 | end 366 | 367 | assert_raises(TypeError) do 368 | @ctx.call_prop('id', {'key' => Object.new}) 369 | end 370 | end 371 | end 372 | 373 | describe "string encoding" do 374 | before do 375 | @ctx.eval_string('function id(str) { return str }') 376 | @ctx.eval_string('function len(str) { return str.length }') 377 | end 378 | 379 | def test_string_utf8_encoding 380 | str = @ctx.eval_string('"foo"') 381 | assert_equal 'foo', str 382 | assert_equal Encoding::UTF_8, str.encoding 383 | end 384 | 385 | def test_arguments_are_transcoded_to_utf8 386 | # "foo" as UTF-16LE bytes 387 | str = "\x66\x00\x6f\x00\x6f\00".force_encoding(Encoding::UTF_16LE) 388 | str = @ctx.call_prop('id', str) 389 | assert_equal 'foo', str 390 | assert_equal Encoding::UTF_8, str.encoding 391 | end 392 | 393 | def test_surrogate_pairs 394 | # Smiling emoji 395 | str = "\u{1f604}".encode("UTF-8") 396 | assert_equal str, @ctx.call_prop('id', str) 397 | assert_equal 2, @ctx.call_prop('len', str) 398 | assert_equal str, @ctx.eval_string("'#{str}'") 399 | assert_equal 2, @ctx.eval_string("'#{str}'.length") 400 | 401 | # US flag emoji 402 | str = "\u{1f1fa}\u{1f1f8}".force_encoding("UTF-8") 403 | assert_equal str, @ctx.call_prop('id', str) 404 | assert_equal 4, @ctx.call_prop('len', str) 405 | assert_equal str, @ctx.eval_string("'#{str}'") 406 | assert_equal 4, @ctx.eval_string("'#{str}'.length") 407 | end 408 | 409 | def test_invalid_input_data 410 | str = "\xde\xad\xbe\xef".force_encoding('UTF-8') 411 | assert_raises(EncodingError) do 412 | assert_equal str, @ctx.call_prop('id', str) 413 | end 414 | end 415 | 416 | def test_valid_output_data 417 | ranges = [ 418 | (0x0000..0xD7FF), 419 | (0xE000..0xFFFF), 420 | (0x010000..0x10FFFF) 421 | ] 422 | 423 | # Pick some code points 424 | challenge = [] 425 | n = 10000 426 | n.times do 427 | challenge << rand(ranges.sample) 428 | end 429 | 430 | str = @ctx.eval_string(<<-JS) 431 | var res = []; 432 | var codepoints = #{challenge.inspect}; 433 | for (var i = 0; i < codepoints.length; i++) { 434 | var codepoint = codepoints[i]; 435 | if (codepoint > 0xFFFF) { 436 | codepoint -= 0x10000; 437 | var highSurrogate = (codepoint >> 10) + 0xD800; 438 | var lowSurrogate = (codepoint % 0x400) + 0xDC00; 439 | res.push(String.fromCharCode(highSurrogate, lowSurrogate)); 440 | } else { 441 | res.push(String.fromCharCode(codepoints[i])); 442 | } 443 | } 444 | res.join("") 445 | JS 446 | 447 | str.each_codepoint do |code| 448 | assert_equal challenge.shift, code 449 | end 450 | end 451 | 452 | def test_invalid_output_data 453 | assert_raises(EncodingError) do 454 | @ctx.eval_string(<<-JS) 455 | ({data:String.fromCharCode(0xD800 + 10)}) 456 | JS 457 | end 458 | end 459 | end 460 | 461 | describe "ComplexObject instance" do 462 | def test_survives_bad_people 463 | Duktape::ComplexObject.instance_variable_set(:@instance, nil) 464 | # Generate some garbage 465 | 100.times { Array.new(1000) { " " * 100 } } 466 | GC.start 467 | assert Duktape::ComplexObject.instance 468 | end 469 | end 470 | 471 | describe "custom ComplexObject" do 472 | def options 473 | super.merge(complex_object: false) 474 | end 475 | 476 | def test_complex_object 477 | assert_equal false, @ctx.eval_string("(function() {})") 478 | end 479 | 480 | def test_hash_complex_object 481 | assert_equal Hash.new, @ctx.eval_string("({foo:(function() {})})") 482 | end 483 | 484 | def test_array_complex_object 485 | assert_equal [1, false], @ctx.eval_string("[1, function() {}]") 486 | end 487 | 488 | def test_keeps_other 489 | assert_equal({'foo' => false}, @ctx.eval_string("({foo:false})")) 490 | end 491 | 492 | def test_maintains_reference 493 | @ctx = Duktape::Context.new(complex_object: "hello") 494 | # Generate some garbage 495 | 100.times { Array.new(1000) { " " * 100 } } 496 | GC.start 497 | assert_equal "hello", @ctx.complex_object 498 | end 499 | end 500 | 501 | def test_default_stacktrace 502 | res = @ctx.eval_string <<-EOF 503 | function run() { 504 | try { 505 | throw new Error; 506 | } catch (err) { 507 | return err.stack.toString(); 508 | } 509 | } 510 | 511 | run(); 512 | EOF 513 | 514 | assert_includes res, "(duktape):3" 515 | end 516 | 517 | def test_filename_stacktrace 518 | res = @ctx.eval_string <<-EOF, __FILE__ 519 | function run() { 520 | try { 521 | throw new Error; 522 | } catch (err) { 523 | return err.stack.toString(); 524 | } 525 | } 526 | 527 | run(); 528 | EOF 529 | 530 | assert_includes res, "#{__FILE__}:3" 531 | end 532 | 533 | describe "modules" do 534 | def test_required_undefined 535 | assert_equal 'undefined', 536 | @ctx.eval_string('typeof require') 537 | end 538 | 539 | def test_module_undefined 540 | assert_equal 'undefined', 541 | @ctx.eval_string('typeof module') 542 | end 543 | 544 | def test_exports_undefined 545 | assert_equal 'undefined', 546 | @ctx.eval_string('typeof exports') 547 | end 548 | end 549 | 550 | ## Previous bugs in Duktape 551 | describe "previous bugs" do 552 | def test_tailcall_bug 553 | # Tail calls sometimes messes up the parent frame 554 | res = @ctx.eval_string <<-EOF 555 | var reduce = function(obj, iterator, memo) { 556 | return obj.reduce(iterator, memo); 557 | }; 558 | 559 | function replace(array, shallow) { 560 | return reduce(array, function(memo, value) { 561 | return memo.concat(shallow); 562 | }, []); 563 | } 564 | 565 | JSON.stringify(replace([1, 2], 1)); 566 | EOF 567 | 568 | assert_equal "[1,1]", res 569 | end 570 | 571 | def test_bind_constructor 572 | # Function.prototype.bind doesn't create constructable functions 573 | res = @ctx.eval_string <<-EOF 574 | function Thing(value) { 575 | this.value = value; 576 | } 577 | 578 | one = Thing.bind(null, 1); 579 | var obj = new one; 580 | obj.value; 581 | EOF 582 | end 583 | end 584 | 585 | describe "popular libraries" do 586 | def test_babel 587 | assert source = File.read(File.expand_path("../fixtures/babel.js", __FILE__)) 588 | 589 | ctx = Duktape::Context.new 590 | ctx.exec_string(source, "(execjs)") 591 | assert_equal 64, ctx.call_prop(["babel", "eval"], "((x) => x * x)(8)") 592 | end 593 | 594 | def test_coffee_script 595 | assert source = File.read(File.expand_path("../fixtures/coffee-script.js", __FILE__)) 596 | 597 | ctx = Duktape::Context.new 598 | ctx.exec_string(source, "(execjs)") 599 | assert_equal 64, ctx.call_prop(["CoffeeScript", "eval"], "((x) -> x * x)(8)") 600 | end 601 | 602 | def test_uglify 603 | assert source = File.read(File.expand_path("../fixtures/uglify.js", __FILE__)) 604 | 605 | ctx = Duktape::Context.new 606 | ctx.exec_string(source, "(execjs)") 607 | 608 | assert_equal "function foo(bar){return bar}", 609 | ctx.call_prop(["uglify"], "function foo(bar) {\n return bar;\n}") 610 | end 611 | end 612 | end 613 | -------------------------------------------------------------------------------- /ext/duktape/duktape_ext.c: -------------------------------------------------------------------------------- 1 | #include "ruby.h" 2 | #include "ruby/encoding.h" 3 | #include "duktape.h" 4 | 5 | static VALUE mDuktape; 6 | static VALUE cContext; 7 | static VALUE cComplexObject; 8 | static VALUE oComplexObject; 9 | 10 | static VALUE eUnimplementedError; 11 | static VALUE eUnsupportedError; 12 | static VALUE eInternalError; 13 | static VALUE eAllocError; 14 | static VALUE eAssertionError; 15 | static VALUE eAPIError; 16 | static VALUE eUncaughtError; 17 | 18 | static VALUE eError; 19 | static VALUE eEvalError; 20 | static VALUE eRangeError; 21 | static VALUE eReferenceError; 22 | static VALUE eSyntaxError; 23 | static VALUE eTypeError; 24 | static VALUE eURIError; 25 | static rb_encoding *utf16enc; 26 | 27 | static VALUE sDefaultFilename; 28 | static ID id_complex_object; 29 | 30 | static void error_handler(duk_context *, int, const char *); 31 | static int ctx_push_hash_element(VALUE key, VALUE val, VALUE extra); 32 | 33 | static unsigned long 34 | utf8_to_uv(const char *p, long *lenp); 35 | 36 | #define clean_raise(ctx, ...) (duk_set_top(ctx, 0), rb_raise(__VA_ARGS__)) 37 | #define clean_raise_exc(ctx, ...) (duk_set_top(ctx, 0), rb_exc_raise(__VA_ARGS__)) 38 | 39 | struct state { 40 | duk_context *ctx; 41 | VALUE complex_object; 42 | int was_complex; 43 | }; 44 | 45 | static void ctx_dealloc(void *ptr) 46 | { 47 | struct state *state = (struct state *)ptr; 48 | duk_destroy_heap(state->ctx); 49 | free(state); 50 | } 51 | 52 | static void ctx_mark(struct state *state) 53 | { 54 | rb_gc_mark(state->complex_object); 55 | } 56 | 57 | static VALUE ctx_alloc(VALUE klass) 58 | { 59 | duk_context *ctx = duk_create_heap(NULL, NULL, NULL, NULL, error_handler); 60 | 61 | // Undefine require property 62 | duk_push_global_object(ctx); 63 | duk_push_string(ctx, "require"); 64 | duk_del_prop(ctx, -2); 65 | duk_set_top(ctx, 0); 66 | 67 | struct state *state = malloc(sizeof(struct state)); 68 | state->ctx = ctx; 69 | state->complex_object = oComplexObject; 70 | return Data_Wrap_Struct(klass, ctx_mark, ctx_dealloc, state); 71 | } 72 | 73 | static VALUE error_code_class(int code) { 74 | switch (code) { 75 | case DUK_ERR_UNIMPLEMENTED_ERROR: 76 | return eUnimplementedError; 77 | case DUK_ERR_UNSUPPORTED_ERROR: 78 | return eUnsupportedError; 79 | case DUK_ERR_INTERNAL_ERROR: 80 | return eInternalError; 81 | case DUK_ERR_ALLOC_ERROR: 82 | return eAllocError; 83 | case DUK_ERR_ASSERTION_ERROR: 84 | return eAssertionError; 85 | case DUK_ERR_API_ERROR: 86 | return eAPIError; 87 | case DUK_ERR_UNCAUGHT_ERROR: 88 | return eUncaughtError; 89 | 90 | case DUK_ERR_ERROR: 91 | return eError; 92 | case DUK_ERR_EVAL_ERROR: 93 | return eEvalError; 94 | case DUK_ERR_RANGE_ERROR: 95 | return eRangeError; 96 | case DUK_ERR_REFERENCE_ERROR: 97 | return eReferenceError; 98 | case DUK_ERR_SYNTAX_ERROR: 99 | return eSyntaxError; 100 | case DUK_ERR_TYPE_ERROR: 101 | return eTypeError; 102 | case DUK_ERR_URI_ERROR: 103 | return eURIError; 104 | 105 | default: 106 | return eInternalError; 107 | } 108 | } 109 | 110 | static VALUE error_name_class(const char* name) 111 | { 112 | if (strcmp(name, "EvalError") == 0) { 113 | return eEvalError; 114 | } else if (strcmp(name, "RangeError") == 0) { 115 | return eRangeError; 116 | } else if (strcmp(name, "ReferenceError") == 0) { 117 | return eReferenceError; 118 | } else if (strcmp(name, "SyntaxError") == 0) { 119 | return eSyntaxError; 120 | } else if (strcmp(name, "TypeError") == 0) { 121 | return eTypeError; 122 | } else if (strcmp(name, "URIError") == 0) { 123 | return eURIError; 124 | } else { 125 | return eError; 126 | } 127 | } 128 | 129 | static VALUE encode_cesu8(struct state *state, VALUE str) 130 | { 131 | duk_context *ctx = state->ctx; 132 | VALUE res = rb_str_new(0, 0); 133 | 134 | VALUE utf16 = rb_str_conv_enc(str, rb_enc_get(str), utf16enc); 135 | if (utf16 == str && rb_enc_get(str) != utf16enc) { 136 | clean_raise(ctx, rb_eEncodingError, "cannot convert Ruby string to UTF-16"); 137 | } 138 | 139 | long len = RSTRING_LEN(utf16) / 2; 140 | unsigned short *bytes = (unsigned short *)RSTRING_PTR(utf16); 141 | 142 | char buf[8]; 143 | 144 | for (int i = 0; i < len; i++) { 145 | int length = rb_uv_to_utf8(buf, bytes[i]); 146 | rb_str_buf_cat(res, (char*)buf, length); 147 | } 148 | 149 | return res; 150 | } 151 | 152 | static VALUE decode_cesu8(struct state *state, VALUE str) 153 | { 154 | duk_context *ctx = state->ctx; 155 | VALUE res = rb_str_new(0, 0); 156 | 157 | const char *ptr = RSTRING_PTR(str); 158 | const char *end = RSTRING_END(str); 159 | long len; 160 | 161 | while (ptr < end) { 162 | len = (end - ptr); 163 | unsigned short code = utf8_to_uv(ptr, &len); 164 | rb_str_buf_cat(res, (char*)&code, 2); 165 | ptr += len; 166 | } 167 | 168 | rb_enc_associate(res, utf16enc); 169 | VALUE utf8res = rb_str_conv_enc(res, utf16enc, rb_utf8_encoding()); 170 | if (utf8res == res) { 171 | clean_raise(ctx, rb_eEncodingError, "cannot convert JavaScript string to UTF-16"); 172 | } 173 | 174 | return utf8res; 175 | } 176 | 177 | static VALUE ctx_stack_to_value(struct state *state, int index) 178 | { 179 | duk_context *ctx = state->ctx; 180 | size_t len; 181 | const char *buf; 182 | int type; 183 | 184 | state->was_complex = 0; 185 | 186 | type = duk_get_type(ctx, index); 187 | switch (type) { 188 | case DUK_TYPE_NULL: 189 | case DUK_TYPE_UNDEFINED: 190 | return Qnil; 191 | 192 | case DUK_TYPE_NUMBER: 193 | return rb_float_new(duk_get_number(ctx, index)); 194 | 195 | case DUK_TYPE_BOOLEAN: 196 | return duk_get_boolean(ctx, index) ? Qtrue : Qfalse; 197 | 198 | case DUK_TYPE_STRING: 199 | buf = duk_get_lstring(ctx, index, &len); 200 | VALUE str = rb_str_new(buf, len); 201 | return decode_cesu8(state, str); 202 | 203 | case DUK_TYPE_OBJECT: 204 | if (duk_is_function(ctx, index)) { 205 | state->was_complex = 1; 206 | return state->complex_object; 207 | } else if (duk_is_array(ctx, index)) { 208 | VALUE ary = rb_ary_new(); 209 | duk_enum(ctx, index, DUK_ENUM_ARRAY_INDICES_ONLY); 210 | while (duk_next(ctx, -1, 1)) { 211 | rb_ary_store(ary, duk_to_int(ctx, -2), ctx_stack_to_value(state, -1)); 212 | duk_pop_2(ctx); 213 | } 214 | duk_pop(ctx); 215 | return ary; 216 | } else if (duk_is_object(ctx, index)) { 217 | VALUE hash = rb_hash_new(); 218 | duk_enum(ctx, index, DUK_ENUM_OWN_PROPERTIES_ONLY); 219 | while (duk_next(ctx, -1, 1)) { 220 | VALUE key = ctx_stack_to_value(state, -2); 221 | VALUE val = ctx_stack_to_value(state, -1); 222 | duk_pop_2(ctx); 223 | if (state->was_complex) 224 | continue; 225 | rb_hash_aset(hash, key, val); 226 | } 227 | duk_pop(ctx); 228 | return hash; 229 | } else { 230 | state->was_complex = 1; 231 | return state->complex_object; 232 | } 233 | 234 | case DUK_TYPE_BUFFER: 235 | case DUK_TYPE_POINTER: 236 | default: 237 | return state->complex_object; 238 | } 239 | 240 | return Qnil; 241 | } 242 | 243 | static void ctx_push_ruby_object(struct state *state, VALUE obj) 244 | { 245 | duk_context *ctx = state->ctx; 246 | duk_idx_t arr_idx; 247 | VALUE str; 248 | 249 | switch (TYPE(obj)) { 250 | case T_FIXNUM: 251 | duk_push_int(ctx, NUM2INT(obj)); 252 | return; 253 | 254 | case T_FLOAT: 255 | duk_push_number(ctx, NUM2DBL(obj)); 256 | return; 257 | 258 | case T_SYMBOL: 259 | #ifdef HAVE_RB_SYM2STR 260 | obj = rb_sym2str(obj); 261 | #else 262 | obj = rb_id2str(SYM2ID(obj)); 263 | #endif 264 | // Intentional fall-through: 265 | 266 | case T_STRING: 267 | str = encode_cesu8(state, obj); 268 | duk_push_lstring(ctx, RSTRING_PTR(str), RSTRING_LEN(str)); 269 | return; 270 | 271 | case T_TRUE: 272 | duk_push_true(ctx); 273 | return; 274 | 275 | case T_FALSE: 276 | duk_push_false(ctx); 277 | return; 278 | 279 | case T_NIL: 280 | duk_push_null(ctx); 281 | return; 282 | 283 | case T_ARRAY: 284 | arr_idx = duk_push_array(ctx); 285 | for (int idx = 0; idx < RARRAY_LEN(obj); idx++) { 286 | ctx_push_ruby_object(state, rb_ary_entry(obj, idx)); 287 | duk_put_prop_index(ctx, arr_idx, idx); 288 | } 289 | return; 290 | 291 | case T_HASH: 292 | duk_push_object(ctx); 293 | rb_hash_foreach(obj, ctx_push_hash_element, (VALUE)state); 294 | return; 295 | 296 | default: 297 | // Cannot convert 298 | break; 299 | } 300 | 301 | clean_raise(ctx, rb_eTypeError, "cannot convert %s", rb_obj_classname(obj)); 302 | } 303 | 304 | static int ctx_push_hash_element(VALUE key, VALUE val, VALUE extra) 305 | { 306 | struct state *state = (struct state*) extra; 307 | duk_context *ctx = state->ctx; 308 | 309 | switch (TYPE(key)) { 310 | case T_SYMBOL: 311 | case T_STRING: 312 | ctx_push_ruby_object(state, key); 313 | break; 314 | default: 315 | clean_raise(ctx, rb_eTypeError, "invalid key type %s", rb_obj_classname(key)); 316 | } 317 | 318 | ctx_push_ruby_object(state, val); 319 | duk_put_prop(ctx, -3); 320 | return ST_CONTINUE; 321 | } 322 | 323 | static void raise_ctx_error(struct state *state) 324 | { 325 | duk_context *ctx = state->ctx; 326 | duk_get_prop_string(ctx, -1, "name"); 327 | const char *name = duk_safe_to_string(ctx, -1); 328 | 329 | duk_get_prop_string(ctx, -2, "message"); 330 | const char *message = duk_to_string(ctx, -1); 331 | 332 | VALUE exc_class = error_name_class(name); 333 | VALUE exc = rb_exc_new2(exc_class, message); 334 | clean_raise_exc(ctx, exc); 335 | } 336 | 337 | /* 338 | * call-seq: 339 | * eval_string(string[, filename]) -> obj 340 | * 341 | * Evaluate JavaScript expression within context returning the value as a Ruby 342 | * object. 343 | * 344 | * ctx.eval_string("40 + 2") #=> 42 345 | * 346 | */ 347 | static VALUE ctx_eval_string(int argc, VALUE *argv, VALUE self) 348 | { 349 | struct state *state; 350 | Data_Get_Struct(self, struct state, state); 351 | 352 | VALUE source; 353 | VALUE filename; 354 | 355 | rb_scan_args(argc, argv, "11", &source, &filename); 356 | 357 | if (NIL_P(filename)) { 358 | filename = sDefaultFilename; 359 | } 360 | 361 | StringValue(source); 362 | StringValue(filename); 363 | 364 | ctx_push_ruby_object(state, source); 365 | ctx_push_ruby_object(state, filename); 366 | 367 | if (duk_pcompile(state->ctx, DUK_COMPILE_EVAL) == DUK_EXEC_ERROR) { 368 | raise_ctx_error(state); 369 | } 370 | 371 | if (duk_pcall(state->ctx, 0) == DUK_EXEC_ERROR) { 372 | raise_ctx_error(state); 373 | } 374 | 375 | VALUE res = ctx_stack_to_value(state, -1); 376 | duk_set_top(state->ctx, 0); 377 | return res; 378 | } 379 | 380 | /* 381 | * call-seq: 382 | * exec_string(string[, filename]) -> nil 383 | * 384 | * Evaluate JavaScript expression within context returning the value as a Ruby 385 | * object. 386 | * 387 | * ctx.exec_string("var foo = 42") 388 | * ctx.eval_string("foo") #=> 42 389 | * 390 | */ 391 | static VALUE ctx_exec_string(int argc, VALUE *argv, VALUE self) 392 | { 393 | struct state *state; 394 | Data_Get_Struct(self, struct state, state); 395 | 396 | VALUE source; 397 | VALUE filename; 398 | 399 | rb_scan_args(argc, argv, "11", &source, &filename); 400 | 401 | if (NIL_P(filename)) { 402 | filename = sDefaultFilename; 403 | } 404 | 405 | StringValue(source); 406 | StringValue(filename); 407 | 408 | ctx_push_ruby_object(state, source); 409 | ctx_push_ruby_object(state, filename); 410 | 411 | if (duk_pcompile(state->ctx, 0) == DUK_EXEC_ERROR) { 412 | raise_ctx_error(state); 413 | } 414 | 415 | if (duk_pcall(state->ctx, 0) == DUK_EXEC_ERROR) { 416 | raise_ctx_error(state); 417 | } 418 | 419 | duk_set_top(state->ctx, 0); 420 | return Qnil; 421 | } 422 | 423 | static void ctx_get_one_prop(struct state *state, VALUE name, int strict) 424 | { 425 | duk_context *ctx = state->ctx; 426 | 427 | // Don't allow prop access on undefined/null 428 | if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_NULL)) { 429 | clean_raise(ctx, eTypeError, "invalid base value"); 430 | } 431 | 432 | duk_push_lstring(ctx, RSTRING_PTR(name), RSTRING_LEN(name)); 433 | duk_bool_t exists = duk_get_prop(ctx, -2); 434 | 435 | if (!exists && strict) { 436 | const char *str = StringValueCStr(name); 437 | clean_raise(ctx, eReferenceError, "identifier '%s' undefined", str); 438 | } 439 | } 440 | 441 | static void ctx_get_nested_prop(struct state *state, VALUE props) 442 | { 443 | duk_context *ctx = state->ctx; 444 | 445 | switch (TYPE(props)) { 446 | case T_STRING: 447 | duk_push_global_object(ctx); 448 | ctx_get_one_prop(state, props, 1); 449 | return; 450 | 451 | case T_ARRAY: 452 | duk_push_global_object(ctx); 453 | 454 | long len = RARRAY_LEN(props); 455 | for (int i = 0; i < len; i++) { 456 | VALUE item = rb_ary_entry(props, i); 457 | Check_Type(item, T_STRING); 458 | 459 | // Only do a strict check on the first item 460 | ctx_get_one_prop(state, item, i == 0); 461 | } 462 | return; 463 | 464 | default: 465 | clean_raise(ctx, rb_eTypeError, "wrong argument type %s (expected String or Array)", rb_obj_classname(props)); 466 | return; 467 | } 468 | } 469 | 470 | /* 471 | * call-seq: 472 | * get_prop(name) -> obj 473 | * get_prop([names,...]) -> obj 474 | * 475 | * Access the property of the global object. An Array of names can be given 476 | * to access the property on a nested object. 477 | * 478 | * ctx.exec_string("var n = 42", "foo.js") 479 | * ctx.get_prop("n") #=> 42 480 | * 481 | * ctx.get_prop(["Math", "PI"]) #=> 3.14 482 | * 483 | */ 484 | static VALUE ctx_get_prop(VALUE self, VALUE prop) 485 | { 486 | struct state *state; 487 | Data_Get_Struct(self, struct state, state); 488 | 489 | ctx_get_nested_prop(state, prop); 490 | 491 | VALUE res = ctx_stack_to_value(state, -1); 492 | duk_set_top(state->ctx, 0); 493 | return res; 494 | } 495 | 496 | 497 | /* 498 | * call-seq: 499 | * call_prop(name, params,...) -> obj 500 | * call_prop([names,...], params,...) -> obj 501 | * 502 | * Call a function defined in the global scope with the given parameters. An 503 | * Array of names can be given to call a function on a nested object. 504 | * 505 | * ctx.call_prop("parseInt", "42") #=> 42 506 | * ctx.call_prop(["Math", "pow"], 2, 10) #=> 1024 507 | * 508 | */ 509 | static VALUE ctx_call_prop(int argc, VALUE* argv, VALUE self) 510 | { 511 | struct state *state; 512 | Data_Get_Struct(self, struct state, state); 513 | 514 | VALUE prop; 515 | VALUE *prop_args; 516 | rb_scan_args(argc, argv, "1*", &prop, &prop_args); 517 | 518 | ctx_get_nested_prop(state, prop); 519 | 520 | // Swap receiver and function 521 | duk_swap_top(state->ctx, -2); 522 | 523 | // Push arguments 524 | for (int i = 1; i < argc; i++) { 525 | ctx_push_ruby_object(state, argv[i]); 526 | } 527 | 528 | if (duk_pcall_method(state->ctx, (argc - 1)) == DUK_EXEC_ERROR) { 529 | raise_ctx_error(state); 530 | } 531 | 532 | VALUE res = ctx_stack_to_value(state, -1); 533 | duk_set_top(state->ctx, 0); 534 | return res; 535 | } 536 | 537 | /* 538 | * :nodoc: 539 | * 540 | * Checks that we are in a fine state 541 | */ 542 | static VALUE ctx_is_valid(VALUE self) 543 | { 544 | struct state *state; 545 | Data_Get_Struct(self, struct state, state); 546 | 547 | if (duk_is_valid_index(state->ctx, -1)) { 548 | return Qfalse; 549 | } else { 550 | return Qtrue; 551 | } 552 | } 553 | 554 | static void error_handler(duk_context *ctx, int code, const char *msg) 555 | { 556 | clean_raise(ctx, error_code_class(code), "%s", msg); 557 | } 558 | 559 | VALUE complex_object_instance(VALUE self) 560 | { 561 | return oComplexObject; 562 | } 563 | 564 | /* 565 | * call-seq: 566 | * Context.new 567 | * Context.new(complex_object: obj) 568 | * 569 | * Returns a new JavaScript evaluation context. 570 | * 571 | */ 572 | static VALUE ctx_initialize(int argc, VALUE *argv, VALUE self) 573 | { 574 | struct state *state; 575 | Data_Get_Struct(self, struct state, state); 576 | 577 | VALUE options; 578 | rb_scan_args(argc, argv, ":", &options); 579 | if (!NIL_P(options)) 580 | state->complex_object = rb_hash_lookup2(options, ID2SYM(id_complex_object), state->complex_object); 581 | 582 | return Qnil; 583 | } 584 | 585 | /* 586 | * call-seq: 587 | * complex_object -> obj 588 | * 589 | * Returns the default complex object, the value that would be returned if a 590 | * JavaScript object had no representation in Ruby, such as a JavaScript 591 | * Function. See also Context::new. 592 | * 593 | * ctx.complex_object #=> # 594 | * 595 | */ 596 | static VALUE ctx_complex_object(VALUE self) 597 | { 598 | struct state *state; 599 | Data_Get_Struct(self, struct state, state); 600 | 601 | return state->complex_object; 602 | } 603 | 604 | void Init_duktape_ext() 605 | { 606 | int one = 1; 607 | if (*(char*)(&one) == 1) { 608 | utf16enc = rb_enc_find("UTF-16LE"); 609 | } else { 610 | utf16enc = rb_enc_find("UTF-16BE"); 611 | } 612 | id_complex_object = rb_intern("complex_object"); 613 | 614 | mDuktape = rb_define_module("Duktape"); 615 | cContext = rb_define_class_under(mDuktape, "Context", rb_cObject); 616 | cComplexObject = rb_define_class_under(mDuktape, "ComplexObject", rb_cObject); 617 | 618 | eInternalError = rb_define_class_under(mDuktape, "InternalError", rb_eStandardError); 619 | eUnimplementedError = rb_define_class_under(mDuktape, "UnimplementedError", eInternalError); 620 | eUnsupportedError = rb_define_class_under(mDuktape, "UnsupportedError", eInternalError); 621 | eAllocError = rb_define_class_under(mDuktape, "AllocError", eInternalError); 622 | eAssertionError = rb_define_class_under(mDuktape, "AssertionError", eInternalError); 623 | eAPIError = rb_define_class_under(mDuktape, "APIError", eInternalError); 624 | eUncaughtError = rb_define_class_under(mDuktape, "UncaughtError", eInternalError); 625 | 626 | eError = rb_define_class_under(mDuktape, "Error", rb_eStandardError); 627 | eEvalError = rb_define_class_under(mDuktape, "EvalError", eError); 628 | eRangeError = rb_define_class_under(mDuktape, "RangeError", eError); 629 | eReferenceError = rb_define_class_under(mDuktape, "ReferenceError", eError); 630 | eSyntaxError = rb_define_class_under(mDuktape, "SyntaxError", eError); 631 | eTypeError = rb_define_class_under(mDuktape, "TypeError", eError); 632 | eURIError = rb_define_class_under(mDuktape, "URIError", eError); 633 | 634 | rb_define_alloc_func(cContext, ctx_alloc); 635 | 636 | rb_define_method(cContext, "initialize", ctx_initialize, -1); 637 | rb_define_method(cContext, "complex_object", ctx_complex_object, 0); 638 | rb_define_method(cContext, "eval_string", ctx_eval_string, -1); 639 | rb_define_method(cContext, "exec_string", ctx_exec_string, -1); 640 | rb_define_method(cContext, "get_prop", ctx_get_prop, 1); 641 | rb_define_method(cContext, "call_prop", ctx_call_prop, -1); 642 | rb_define_method(cContext, "_valid?", ctx_is_valid, 0); 643 | 644 | oComplexObject = rb_obj_alloc(cComplexObject); 645 | rb_define_singleton_method(cComplexObject, "instance", complex_object_instance, 0); 646 | rb_ivar_set(cComplexObject, rb_intern("duktape.instance"), oComplexObject); 647 | 648 | sDefaultFilename = rb_str_new2("(duktape)"); 649 | OBJ_FREEZE(sDefaultFilename); 650 | rb_global_variable(&sDefaultFilename); 651 | } 652 | 653 | 654 | /* UTF8 crap which is not exposed by Ruby */ 655 | 656 | static const unsigned long utf8_limits[] = { 657 | 0x0, /* 1 */ 658 | 0x80, /* 2 */ 659 | 0x800, /* 3 */ 660 | 0x10000, /* 4 */ 661 | 0x200000, /* 5 */ 662 | 0x4000000, /* 6 */ 663 | 0x80000000, /* 7 */ 664 | }; 665 | 666 | static unsigned long 667 | utf8_to_uv(const char *p, long *lenp) 668 | { 669 | int c = *p++ & 0xff; 670 | unsigned long uv = c; 671 | long n; 672 | 673 | if (!(uv & 0x80)) { 674 | *lenp = 1; 675 | return uv; 676 | } 677 | if (!(uv & 0x40)) { 678 | *lenp = 1; 679 | rb_raise(rb_eArgError, "malformed UTF-8 character"); 680 | } 681 | 682 | if (!(uv & 0x20)) { n = 2; uv &= 0x1f; } 683 | else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; } 684 | else if (!(uv & 0x08)) { n = 4; uv &= 0x07; } 685 | else if (!(uv & 0x04)) { n = 5; uv &= 0x03; } 686 | else if (!(uv & 0x02)) { n = 6; uv &= 0x01; } 687 | else { 688 | *lenp = 1; 689 | rb_raise(rb_eArgError, "malformed UTF-8 character"); 690 | } 691 | if (n > *lenp) { 692 | rb_raise(rb_eArgError, "malformed UTF-8 character (expected %ld bytes, given %ld bytes)", 693 | n, *lenp); 694 | } 695 | *lenp = n--; 696 | if (n != 0) { 697 | while (n--) { 698 | c = *p++ & 0xff; 699 | if ((c & 0xc0) != 0x80) { 700 | *lenp -= n + 1; 701 | rb_raise(rb_eArgError, "malformed UTF-8 character"); 702 | } 703 | else { 704 | c &= 0x3f; 705 | uv = uv << 6 | c; 706 | } 707 | } 708 | } 709 | n = *lenp - 1; 710 | if (uv < utf8_limits[n]) { 711 | rb_raise(rb_eArgError, "redundant UTF-8 sequence"); 712 | } 713 | return uv; 714 | } 715 | -------------------------------------------------------------------------------- /ext/duktape/duktape.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Duktape public API for Duktape 1.3.0. 3 | * See the API reference for documentation on call semantics. 4 | * The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED 5 | * include guard. Other parts of the header are Duktape 6 | * internal and related to platform/compiler/feature detection. 7 | * 8 | * Git commit 675165f35ea3a5bac34ff4d0a58b007cc2f442dc (v1.3.0). 9 | * 10 | * See Duktape AUTHORS.rst and LICENSE.txt for copyright and 11 | * licensing information. 12 | */ 13 | 14 | /* LICENSE.txt */ 15 | /* 16 | * =============== 17 | * Duktape license 18 | * =============== 19 | * 20 | * (http://opensource.org/licenses/MIT) 21 | * 22 | * Copyright (c) 2013-2015 by Duktape authors (see AUTHORS.rst) 23 | * 24 | * Permission is hereby granted, free of charge, to any person obtaining a copy 25 | * of this software and associated documentation files (the "Software"), to deal 26 | * in the Software without restriction, including without limitation the rights 27 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 28 | * copies of the Software, and to permit persons to whom the Software is 29 | * furnished to do so, subject to the following conditions: 30 | * 31 | * The above copyright notice and this permission notice shall be included in 32 | * all copies or substantial portions of the Software. 33 | * 34 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 35 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 36 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 37 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 38 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 39 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 40 | * THE SOFTWARE. 41 | */ 42 | 43 | /* AUTHORS.rst */ 44 | /* 45 | * =============== 46 | * Duktape authors 47 | * =============== 48 | * 49 | * Copyright 50 | * ========= 51 | * 52 | * Duktape copyrights are held by its authors. Each author has a copyright 53 | * to their contribution, and agrees to irrevocably license the contribution 54 | * under the Duktape ``LICENSE.txt``. 55 | * 56 | * Authors 57 | * ======= 58 | * 59 | * Please include an e-mail address, a link to your GitHub profile, or something 60 | * similar to allow your contribution to be identified accurately. 61 | * 62 | * The following people have contributed code, website contents, or Wiki contents, 63 | * and agreed to irrevocably license their contributions under the Duktape 64 | * ``LICENSE.txt`` (in order of appearance): 65 | * 66 | * * Sami Vaarala 67 | * * Niki Dobrev 68 | * * Andreas \u00d6man 69 | * * L\u00e1szl\u00f3 Lang\u00f3 70 | * * Legimet 71 | * * Karl Skomski 72 | * * Bruce Pascoe 73 | * 74 | * Other contributions 75 | * =================== 76 | * 77 | * The following people have contributed something other than code (e.g. reported 78 | * bugs, provided ideas, etc; roughly in order of appearance): 79 | * 80 | * * Greg Burns 81 | * * Anthony Rabine 82 | * * Carlos Costa 83 | * * Aur\u00e9lien Bouilland 84 | * * Preet Desai (Pris Matic) 85 | * * judofyr (http://www.reddit.com/user/judofyr) 86 | * * Jason Woofenden 87 | * * Micha\u0142 Przyby\u015b 88 | * * Anthony Howe 89 | * * Conrad Pankoff 90 | * * Jim Schimpf 91 | * * Rajaran Gaunker (https://github.com/zimbabao) 92 | * * Andreas \u00d6man 93 | * * Doug Sanden 94 | * * Josh Engebretson (https://github.com/JoshEngebretson) 95 | * * Remo Eichenberger (https://github.com/remoe) 96 | * * Mamod Mehyar (https://github.com/mamod) 97 | * * David Demelier (https://github.com/markand) 98 | * * Tim Caswell (https://github.com/creationix) 99 | * * Mitchell Blank Jr (https://github.com/mitchblank) 100 | * * https://github.com/yushli 101 | * * Seo Sanghyeon (https://github.com/sanxiyn) 102 | * * Han ChoongWoo (https://github.com/tunz) 103 | * * Joshua Peek (https://github.com/josh) 104 | * * Bruce E. Pascoe (https://github.com/fatcerberus) 105 | * * https://github.com/Kelledin 106 | * * https://github.com/sstruchtrup 107 | * * Michael Drake (https://github.com/tlsa) 108 | * * https://github.com/chris-y 109 | * 110 | * If you are accidentally missing from this list, send me an e-mail 111 | * (``sami.vaarala@iki.fi``) and I'll fix the omission. 112 | */ 113 | 114 | #ifndef DUKTAPE_H_INCLUDED 115 | #define DUKTAPE_H_INCLUDED 116 | 117 | #define DUK_SINGLE_FILE 118 | 119 | /* External duk_config.h provides platform/compiler/OS dependent 120 | * typedefs and macros, and DUK_USE_xxx config options so that 121 | * the rest of Duktape doesn't need to do any feature detection. 122 | */ 123 | #include "duk_config.h" 124 | 125 | /* 126 | * BEGIN PUBLIC API 127 | */ 128 | 129 | #ifndef DUK_API_PUBLIC_H_INCLUDED 130 | #define DUK_API_PUBLIC_H_INCLUDED 131 | 132 | /* 133 | * Avoid C++ name mangling 134 | */ 135 | 136 | #ifdef __cplusplus 137 | extern "C" { 138 | #endif 139 | 140 | /* 141 | * Some defines forwarded from feature detection 142 | */ 143 | 144 | #undef DUK_API_VARIADIC_MACROS 145 | #ifdef DUK_USE_VARIADIC_MACROS 146 | #define DUK_API_VARIADIC_MACROS 147 | #endif 148 | 149 | #define DUK_API_NORETURN(decl) DUK_NORETURN(decl) 150 | 151 | /* 152 | * Public API specific typedefs 153 | * 154 | * Many types are wrapped by Duktape for portability to rare platforms 155 | * where e.g. 'int' is a 16-bit type. See practical typing discussion 156 | * in Duktape web documentation. 157 | */ 158 | 159 | struct duk_memory_functions; 160 | struct duk_function_list_entry; 161 | struct duk_number_list_entry; 162 | 163 | /* duk_context is now defined in duk_config.h because it may also be 164 | * referenced there by prototypes. 165 | */ 166 | typedef struct duk_memory_functions duk_memory_functions; 167 | typedef struct duk_function_list_entry duk_function_list_entry; 168 | typedef struct duk_number_list_entry duk_number_list_entry; 169 | 170 | typedef duk_ret_t (*duk_c_function)(duk_context *ctx); 171 | typedef void *(*duk_alloc_function) (void *udata, duk_size_t size); 172 | typedef void *(*duk_realloc_function) (void *udata, void *ptr, duk_size_t size); 173 | typedef void (*duk_free_function) (void *udata, void *ptr); 174 | typedef void (*duk_fatal_function) (duk_context *ctx, duk_errcode_t code, const char *msg); 175 | typedef void (*duk_decode_char_function) (void *udata, duk_codepoint_t codepoint); 176 | typedef duk_codepoint_t (*duk_map_char_function) (void *udata, duk_codepoint_t codepoint); 177 | typedef duk_ret_t (*duk_safe_call_function) (duk_context *ctx); 178 | typedef duk_size_t (*duk_debug_read_function) (void *udata, char *buffer, duk_size_t length); 179 | typedef duk_size_t (*duk_debug_write_function) (void *udata, const char *buffer, duk_size_t length); 180 | typedef duk_size_t (*duk_debug_peek_function) (void *udata); 181 | typedef void (*duk_debug_read_flush_function) (void *udata); 182 | typedef void (*duk_debug_write_flush_function) (void *udata); 183 | typedef void (*duk_debug_detached_function) (void *udata); 184 | 185 | struct duk_memory_functions { 186 | duk_alloc_function alloc_func; 187 | duk_realloc_function realloc_func; 188 | duk_free_function free_func; 189 | void *udata; 190 | }; 191 | 192 | struct duk_function_list_entry { 193 | const char *key; 194 | duk_c_function value; 195 | duk_idx_t nargs; 196 | }; 197 | 198 | struct duk_number_list_entry { 199 | const char *key; 200 | duk_double_t value; 201 | }; 202 | 203 | /* 204 | * Constants 205 | */ 206 | 207 | /* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code 208 | * to #ifdef against Duktape API version. The same value is also available 209 | * to Ecmascript code in Duktape.version. Unofficial development snapshots 210 | * have 99 for patch level (e.g. 0.10.99 would be a development version 211 | * after 0.10.0 but before the next official release). 212 | */ 213 | #define DUK_VERSION 10300L 214 | 215 | /* Git describe for Duktape build. Useful for non-official snapshot builds 216 | * so that application code can easily log which Duktape snapshot was used. 217 | * Not available in the Ecmascript environment. 218 | */ 219 | #define DUK_GIT_DESCRIBE "v1.3.0" 220 | 221 | /* Duktape debug protocol version used by this build. */ 222 | #define DUK_DEBUG_PROTOCOL_VERSION 1 223 | 224 | /* Used to represent invalid index; if caller uses this without checking, 225 | * this index will map to a non-existent stack entry. Also used in some 226 | * API calls as a marker to denote "no value". 227 | */ 228 | #define DUK_INVALID_INDEX DUK_IDX_MIN 229 | 230 | /* Indicates that a native function does not have a fixed number of args, 231 | * and the argument stack should not be capped/extended at all. 232 | */ 233 | #define DUK_VARARGS ((duk_int_t) (-1)) 234 | 235 | /* Number of value stack entries (in addition to actual call arguments) 236 | * guaranteed to be allocated on entry to a Duktape/C function. 237 | */ 238 | #define DUK_API_ENTRY_STACK 64 239 | 240 | /* Value types, used by e.g. duk_get_type() */ 241 | #define DUK_TYPE_NONE 0 /* no value, e.g. invalid index */ 242 | #define DUK_TYPE_UNDEFINED 1 /* Ecmascript undefined */ 243 | #define DUK_TYPE_NULL 2 /* Ecmascript null */ 244 | #define DUK_TYPE_BOOLEAN 3 /* Ecmascript boolean: 0 or 1 */ 245 | #define DUK_TYPE_NUMBER 4 /* Ecmascript number: double */ 246 | #define DUK_TYPE_STRING 5 /* Ecmascript string: CESU-8 / extended UTF-8 encoded */ 247 | #define DUK_TYPE_OBJECT 6 /* Ecmascript object: includes objects, arrays, functions, threads */ 248 | #define DUK_TYPE_BUFFER 7 /* fixed or dynamic, garbage collected byte buffer */ 249 | #define DUK_TYPE_POINTER 8 /* raw void pointer */ 250 | #define DUK_TYPE_LIGHTFUNC 9 /* lightweight function pointer */ 251 | 252 | /* Value mask types, used by e.g. duk_get_type_mask() */ 253 | #define DUK_TYPE_MASK_NONE (1 << DUK_TYPE_NONE) 254 | #define DUK_TYPE_MASK_UNDEFINED (1 << DUK_TYPE_UNDEFINED) 255 | #define DUK_TYPE_MASK_NULL (1 << DUK_TYPE_NULL) 256 | #define DUK_TYPE_MASK_BOOLEAN (1 << DUK_TYPE_BOOLEAN) 257 | #define DUK_TYPE_MASK_NUMBER (1 << DUK_TYPE_NUMBER) 258 | #define DUK_TYPE_MASK_STRING (1 << DUK_TYPE_STRING) 259 | #define DUK_TYPE_MASK_OBJECT (1 << DUK_TYPE_OBJECT) 260 | #define DUK_TYPE_MASK_BUFFER (1 << DUK_TYPE_BUFFER) 261 | #define DUK_TYPE_MASK_POINTER (1 << DUK_TYPE_POINTER) 262 | #define DUK_TYPE_MASK_LIGHTFUNC (1 << DUK_TYPE_LIGHTFUNC) 263 | #define DUK_TYPE_MASK_THROW (1 << 10) /* internal flag value: throw if mask doesn't match */ 264 | 265 | /* Coercion hints */ 266 | #define DUK_HINT_NONE 0 /* prefer number, unless input is a Date, in which 267 | * case prefer string (E5 Section 8.12.8) 268 | */ 269 | #define DUK_HINT_STRING 1 /* prefer string */ 270 | #define DUK_HINT_NUMBER 2 /* prefer number */ 271 | 272 | /* Enumeration flags for duk_enum() */ 273 | #define DUK_ENUM_INCLUDE_NONENUMERABLE (1 << 0) /* enumerate non-numerable properties in addition to enumerable */ 274 | #define DUK_ENUM_INCLUDE_INTERNAL (1 << 1) /* enumerate internal properties (regardless of enumerability) */ 275 | #define DUK_ENUM_OWN_PROPERTIES_ONLY (1 << 2) /* don't walk prototype chain, only check own properties */ 276 | #define DUK_ENUM_ARRAY_INDICES_ONLY (1 << 3) /* only enumerate array indices */ 277 | #define DUK_ENUM_SORT_ARRAY_INDICES (1 << 4) /* sort array indices, use with DUK_ENUM_ARRAY_INDICES_ONLY */ 278 | #define DUK_ENUM_NO_PROXY_BEHAVIOR (1 << 5) /* enumerate a proxy object itself without invoking proxy behavior */ 279 | 280 | /* Compilation flags for duk_compile() and duk_eval() */ 281 | #define DUK_COMPILE_EVAL (1 << 0) /* compile eval code (instead of global code) */ 282 | #define DUK_COMPILE_FUNCTION (1 << 1) /* compile function code (instead of global code) */ 283 | #define DUK_COMPILE_STRICT (1 << 2) /* use strict (outer) context for global, eval, or function code */ 284 | #define DUK_COMPILE_SAFE (1 << 3) /* (internal) catch compilation errors */ 285 | #define DUK_COMPILE_NORESULT (1 << 4) /* (internal) omit eval result */ 286 | #define DUK_COMPILE_NOSOURCE (1 << 5) /* (internal) no source string on stack */ 287 | #define DUK_COMPILE_STRLEN (1 << 6) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */ 288 | 289 | /* Flags for duk_def_prop() and its variants */ 290 | #define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */ 291 | #define DUK_DEFPROP_ENUMERABLE (1 << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */ 292 | #define DUK_DEFPROP_CONFIGURABLE (1 << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */ 293 | #define DUK_DEFPROP_HAVE_WRITABLE (1 << 3) /* set/clear writable */ 294 | #define DUK_DEFPROP_HAVE_ENUMERABLE (1 << 4) /* set/clear enumerable */ 295 | #define DUK_DEFPROP_HAVE_CONFIGURABLE (1 << 5) /* set/clear configurable */ 296 | #define DUK_DEFPROP_HAVE_VALUE (1 << 6) /* set value (given on value stack) */ 297 | #define DUK_DEFPROP_HAVE_GETTER (1 << 7) /* set getter (given on value stack) */ 298 | #define DUK_DEFPROP_HAVE_SETTER (1 << 8) /* set setter (given on value stack) */ 299 | #define DUK_DEFPROP_FORCE (1 << 9) /* force change if possible, may still fail for e.g. virtual properties */ 300 | 301 | /* Flags for duk_push_thread_raw() */ 302 | #define DUK_THREAD_NEW_GLOBAL_ENV (1 << 0) /* create a new global environment */ 303 | 304 | /* Flags for duk_push_string_file_raw() */ 305 | #define DUK_STRING_PUSH_SAFE (1 << 0) /* no error if file does not exist */ 306 | 307 | /* Duktape specific error codes */ 308 | #define DUK_ERR_NONE 0 /* no error (e.g. from duk_get_error_code()) */ 309 | #define DUK_ERR_UNIMPLEMENTED_ERROR 50 /* UnimplementedError */ 310 | #define DUK_ERR_UNSUPPORTED_ERROR 51 /* UnsupportedError */ 311 | #define DUK_ERR_INTERNAL_ERROR 52 /* InternalError */ 312 | #define DUK_ERR_ALLOC_ERROR 53 /* AllocError */ 313 | #define DUK_ERR_ASSERTION_ERROR 54 /* AssertionError */ 314 | #define DUK_ERR_API_ERROR 55 /* APIError */ 315 | #define DUK_ERR_UNCAUGHT_ERROR 56 /* UncaughtError */ 316 | 317 | /* Ecmascript E5 specification error codes */ 318 | #define DUK_ERR_ERROR 100 /* Error */ 319 | #define DUK_ERR_EVAL_ERROR 101 /* EvalError */ 320 | #define DUK_ERR_RANGE_ERROR 102 /* RangeError */ 321 | #define DUK_ERR_REFERENCE_ERROR 103 /* ReferenceError */ 322 | #define DUK_ERR_SYNTAX_ERROR 104 /* SyntaxError */ 323 | #define DUK_ERR_TYPE_ERROR 105 /* TypeError */ 324 | #define DUK_ERR_URI_ERROR 106 /* URIError */ 325 | 326 | /* Return codes for C functions (shortcut for throwing an error) */ 327 | #define DUK_RET_UNIMPLEMENTED_ERROR (-DUK_ERR_UNIMPLEMENTED_ERROR) 328 | #define DUK_RET_UNSUPPORTED_ERROR (-DUK_ERR_UNSUPPORTED_ERROR) 329 | #define DUK_RET_INTERNAL_ERROR (-DUK_ERR_INTERNAL_ERROR) 330 | #define DUK_RET_ALLOC_ERROR (-DUK_ERR_ALLOC_ERROR) 331 | #define DUK_RET_ASSERTION_ERROR (-DUK_ERR_ASSERTION_ERROR) 332 | #define DUK_RET_API_ERROR (-DUK_ERR_API_ERROR) 333 | #define DUK_RET_UNCAUGHT_ERROR (-DUK_ERR_UNCAUGHT_ERROR) 334 | #define DUK_RET_ERROR (-DUK_ERR_ERROR) 335 | #define DUK_RET_EVAL_ERROR (-DUK_ERR_EVAL_ERROR) 336 | #define DUK_RET_RANGE_ERROR (-DUK_ERR_RANGE_ERROR) 337 | #define DUK_RET_REFERENCE_ERROR (-DUK_ERR_REFERENCE_ERROR) 338 | #define DUK_RET_SYNTAX_ERROR (-DUK_ERR_SYNTAX_ERROR) 339 | #define DUK_RET_TYPE_ERROR (-DUK_ERR_TYPE_ERROR) 340 | #define DUK_RET_URI_ERROR (-DUK_ERR_URI_ERROR) 341 | 342 | /* Return codes for protected calls (duk_safe_call(), duk_pcall()). */ 343 | #define DUK_EXEC_SUCCESS 0 344 | #define DUK_EXEC_ERROR 1 345 | 346 | /* Log levels */ 347 | #define DUK_LOG_TRACE 0 348 | #define DUK_LOG_DEBUG 1 349 | #define DUK_LOG_INFO 2 350 | #define DUK_LOG_WARN 3 351 | #define DUK_LOG_ERROR 4 352 | #define DUK_LOG_FATAL 5 353 | 354 | /* 355 | * If no variadic macros, __FILE__ and __LINE__ are passed through globals 356 | * which is ugly and not thread safe. 357 | */ 358 | 359 | #ifndef DUK_API_VARIADIC_MACROS 360 | DUK_EXTERNAL_DECL const char *duk_api_global_filename; 361 | DUK_EXTERNAL_DECL duk_int_t duk_api_global_line; 362 | #endif 363 | 364 | /* 365 | * Context management 366 | */ 367 | 368 | DUK_EXTERNAL_DECL 369 | duk_context *duk_create_heap(duk_alloc_function alloc_func, 370 | duk_realloc_function realloc_func, 371 | duk_free_function free_func, 372 | void *heap_udata, 373 | duk_fatal_function fatal_handler); 374 | DUK_EXTERNAL_DECL void duk_destroy_heap(duk_context *ctx); 375 | 376 | #define duk_create_heap_default() \ 377 | duk_create_heap(NULL, NULL, NULL, NULL, NULL) 378 | 379 | /* 380 | * Memory management 381 | * 382 | * Raw functions have no side effects (cannot trigger GC). 383 | */ 384 | 385 | DUK_EXTERNAL_DECL void *duk_alloc_raw(duk_context *ctx, duk_size_t size); 386 | DUK_EXTERNAL_DECL void duk_free_raw(duk_context *ctx, void *ptr); 387 | DUK_EXTERNAL_DECL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size); 388 | DUK_EXTERNAL_DECL void *duk_alloc(duk_context *ctx, duk_size_t size); 389 | DUK_EXTERNAL_DECL void duk_free(duk_context *ctx, void *ptr); 390 | DUK_EXTERNAL_DECL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size); 391 | DUK_EXTERNAL_DECL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs); 392 | DUK_EXTERNAL_DECL void duk_gc(duk_context *ctx, duk_uint_t flags); 393 | 394 | /* 395 | * Error handling 396 | */ 397 | 398 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_throw(duk_context *ctx)); 399 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg)); 400 | 401 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...)); 402 | 403 | #ifdef DUK_API_VARIADIC_MACROS 404 | #define duk_error(ctx,err_code,...) \ 405 | duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (__FILE__), (duk_int_t) (__LINE__), __VA_ARGS__) 406 | #else 407 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...)); 408 | /* One problem with this macro is that expressions like the following fail 409 | * to compile: "(void) duk_error(...)". But because duk_error() is noreturn, 410 | * they make little sense anyway. 411 | */ 412 | #define duk_error \ 413 | (duk_api_global_filename = (const char *) (__FILE__), \ 414 | duk_api_global_line = (duk_int_t) (__LINE__), \ 415 | duk_error_stash) /* last value is func pointer, arguments follow in parens */ 416 | #endif 417 | 418 | DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap)); 419 | #define duk_error_va(ctx,err_code,fmt,ap) \ 420 | duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (__FILE__), (duk_int_t) (__LINE__), (fmt), (ap)) 421 | 422 | /* 423 | * Other state related functions 424 | */ 425 | 426 | DUK_EXTERNAL_DECL duk_bool_t duk_is_strict_call(duk_context *ctx); 427 | DUK_EXTERNAL_DECL duk_bool_t duk_is_constructor_call(duk_context *ctx); 428 | 429 | /* 430 | * Stack management 431 | */ 432 | 433 | DUK_EXTERNAL_DECL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index); 434 | DUK_EXTERNAL_DECL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index); 435 | DUK_EXTERNAL_DECL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index); 436 | DUK_EXTERNAL_DECL void duk_require_valid_index(duk_context *ctx, duk_idx_t index); 437 | 438 | DUK_EXTERNAL_DECL duk_idx_t duk_get_top(duk_context *ctx); 439 | DUK_EXTERNAL_DECL void duk_set_top(duk_context *ctx, duk_idx_t index); 440 | DUK_EXTERNAL_DECL duk_idx_t duk_get_top_index(duk_context *ctx); 441 | DUK_EXTERNAL_DECL duk_idx_t duk_require_top_index(duk_context *ctx); 442 | 443 | /* Although extra/top could be an unsigned type here, using a signed type 444 | * makes the API more robust to calling code calculation errors or corner 445 | * cases (where caller might occasionally come up with negative values). 446 | * Negative values are treated as zero, which is better than casting them 447 | * to a large unsigned number. (This principle is used elsewhere in the 448 | * API too.) 449 | */ 450 | DUK_EXTERNAL_DECL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra); 451 | DUK_EXTERNAL_DECL void duk_require_stack(duk_context *ctx, duk_idx_t extra); 452 | DUK_EXTERNAL_DECL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top); 453 | DUK_EXTERNAL_DECL void duk_require_stack_top(duk_context *ctx, duk_idx_t top); 454 | 455 | /* 456 | * Stack manipulation (other than push/pop) 457 | */ 458 | 459 | DUK_EXTERNAL_DECL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2); 460 | DUK_EXTERNAL_DECL void duk_swap_top(duk_context *ctx, duk_idx_t index); 461 | DUK_EXTERNAL_DECL void duk_dup(duk_context *ctx, duk_idx_t from_index); 462 | DUK_EXTERNAL_DECL void duk_dup_top(duk_context *ctx); 463 | DUK_EXTERNAL_DECL void duk_insert(duk_context *ctx, duk_idx_t to_index); 464 | DUK_EXTERNAL_DECL void duk_replace(duk_context *ctx, duk_idx_t to_index); 465 | DUK_EXTERNAL_DECL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index); 466 | DUK_EXTERNAL_DECL void duk_remove(duk_context *ctx, duk_idx_t index); 467 | DUK_EXTERNAL_DECL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy); 468 | 469 | #define duk_xmove_top(to_ctx,from_ctx,count) \ 470 | duk_xcopymove_raw((to_ctx), (from_ctx), (count), 0 /*is_copy*/) 471 | #define duk_xcopy_top(to_ctx,from_ctx,count) \ 472 | duk_xcopymove_raw((to_ctx), (from_ctx), (count), 1 /*is_copy*/) 473 | 474 | /* 475 | * Push operations 476 | * 477 | * Push functions return the absolute (relative to bottom of frame) 478 | * position of the pushed value for convenience. 479 | * 480 | * Note: duk_dup() is technically a push. 481 | */ 482 | 483 | DUK_EXTERNAL_DECL void duk_push_undefined(duk_context *ctx); 484 | DUK_EXTERNAL_DECL void duk_push_null(duk_context *ctx); 485 | DUK_EXTERNAL_DECL void duk_push_boolean(duk_context *ctx, duk_bool_t val); 486 | DUK_EXTERNAL_DECL void duk_push_true(duk_context *ctx); 487 | DUK_EXTERNAL_DECL void duk_push_false(duk_context *ctx); 488 | DUK_EXTERNAL_DECL void duk_push_number(duk_context *ctx, duk_double_t val); 489 | DUK_EXTERNAL_DECL void duk_push_nan(duk_context *ctx); 490 | DUK_EXTERNAL_DECL void duk_push_int(duk_context *ctx, duk_int_t val); 491 | DUK_EXTERNAL_DECL void duk_push_uint(duk_context *ctx, duk_uint_t val); 492 | DUK_EXTERNAL_DECL const char *duk_push_string(duk_context *ctx, const char *str); 493 | DUK_EXTERNAL_DECL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len); 494 | DUK_EXTERNAL_DECL void duk_push_pointer(duk_context *ctx, void *p); 495 | DUK_EXTERNAL_DECL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...); 496 | DUK_EXTERNAL_DECL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap); 497 | 498 | DUK_EXTERNAL_DECL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags); 499 | #define duk_push_string_file(ctx,path) \ 500 | duk_push_string_file_raw((ctx), (path), 0) 501 | 502 | DUK_EXTERNAL_DECL void duk_push_this(duk_context *ctx); 503 | DUK_EXTERNAL_DECL void duk_push_current_function(duk_context *ctx); 504 | DUK_EXTERNAL_DECL void duk_push_current_thread(duk_context *ctx); 505 | DUK_EXTERNAL_DECL void duk_push_global_object(duk_context *ctx); 506 | DUK_EXTERNAL_DECL void duk_push_heap_stash(duk_context *ctx); 507 | DUK_EXTERNAL_DECL void duk_push_global_stash(duk_context *ctx); 508 | DUK_EXTERNAL_DECL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx); 509 | 510 | DUK_EXTERNAL_DECL duk_idx_t duk_push_object(duk_context *ctx); 511 | DUK_EXTERNAL_DECL duk_idx_t duk_push_array(duk_context *ctx); 512 | DUK_EXTERNAL_DECL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_idx_t nargs); 513 | DUK_EXTERNAL_DECL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic); 514 | DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags); 515 | 516 | #define duk_push_thread(ctx) \ 517 | duk_push_thread_raw((ctx), 0 /*flags*/) 518 | 519 | #define duk_push_thread_new_globalenv(ctx) \ 520 | duk_push_thread_raw((ctx), DUK_THREAD_NEW_GLOBAL_ENV /*flags*/) 521 | 522 | DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...); 523 | 524 | #ifdef DUK_API_VARIADIC_MACROS 525 | #define duk_push_error_object(ctx,err_code,...) \ 526 | duk_push_error_object_raw((ctx), (err_code), (const char *) (__FILE__), (duk_int_t) (__LINE__), __VA_ARGS__) 527 | #else 528 | DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...); 529 | /* Note: parentheses are required so that the comma expression works in assignments. */ 530 | #define duk_push_error_object \ 531 | (duk_api_global_filename = (const char *) (__FILE__), \ 532 | duk_api_global_line = (duk_int_t) (__LINE__), \ 533 | duk_push_error_object_stash) /* last value is func pointer, arguments follow in parens */ 534 | #endif 535 | 536 | DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap); 537 | #define duk_push_error_object_va(ctx,err_code,fmt,ap) \ 538 | duk_push_error_object_va_raw((ctx), (err_code), (const char *) (__FILE__), (duk_int_t) (__LINE__), (fmt), (ap)) 539 | 540 | #define DUK_BUF_FLAG_DYNAMIC (1 << 0) /* internal flag: dynamic buffer */ 541 | #define DUK_BUF_FLAG_EXTERNAL (1 << 1) /* internal flag: external buffer */ 542 | #define DUK_BUF_FLAG_NOZERO (1 << 2) /* internal flag: don't zero allocated buffer */ 543 | 544 | DUK_EXTERNAL_DECL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags); 545 | 546 | #define duk_push_buffer(ctx,size,dynamic) \ 547 | duk_push_buffer_raw((ctx), (size), (dynamic) ? DUK_BUF_FLAG_DYNAMIC : 0); 548 | #define duk_push_fixed_buffer(ctx,size) \ 549 | duk_push_buffer_raw((ctx), (size), 0 /*flags*/) 550 | #define duk_push_dynamic_buffer(ctx,size) \ 551 | duk_push_buffer_raw((ctx), (size), DUK_BUF_FLAG_DYNAMIC /*flags*/) 552 | #define duk_push_external_buffer(ctx) \ 553 | ((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL)) 554 | 555 | #define DUK_BUFOBJ_CREATE_ARRBUF (1 << 4) /* internal flag: create backing ArrayBuffer; keep in one byte */ 556 | #define DUK_BUFOBJ_DUKTAPE_BUFFER 0 557 | #define DUK_BUFOBJ_NODEJS_BUFFER 1 558 | #define DUK_BUFOBJ_ARRAYBUFFER 2 559 | #define DUK_BUFOBJ_DATAVIEW (3 | DUK_BUFOBJ_CREATE_ARRBUF) 560 | #define DUK_BUFOBJ_INT8ARRAY (4 | DUK_BUFOBJ_CREATE_ARRBUF) 561 | #define DUK_BUFOBJ_UINT8ARRAY (5 | DUK_BUFOBJ_CREATE_ARRBUF) 562 | #define DUK_BUFOBJ_UINT8CLAMPEDARRAY (6 | DUK_BUFOBJ_CREATE_ARRBUF) 563 | #define DUK_BUFOBJ_INT16ARRAY (7 | DUK_BUFOBJ_CREATE_ARRBUF) 564 | #define DUK_BUFOBJ_UINT16ARRAY (8 | DUK_BUFOBJ_CREATE_ARRBUF) 565 | #define DUK_BUFOBJ_INT32ARRAY (9 | DUK_BUFOBJ_CREATE_ARRBUF) 566 | #define DUK_BUFOBJ_UINT32ARRAY (10 | DUK_BUFOBJ_CREATE_ARRBUF) 567 | #define DUK_BUFOBJ_FLOAT32ARRAY (11 | DUK_BUFOBJ_CREATE_ARRBUF) 568 | #define DUK_BUFOBJ_FLOAT64ARRAY (12 | DUK_BUFOBJ_CREATE_ARRBUF) 569 | 570 | DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags); 571 | 572 | DUK_EXTERNAL_DECL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr); 573 | 574 | /* 575 | * Pop operations 576 | */ 577 | 578 | DUK_EXTERNAL_DECL void duk_pop(duk_context *ctx); 579 | DUK_EXTERNAL_DECL void duk_pop_n(duk_context *ctx, duk_idx_t count); 580 | DUK_EXTERNAL_DECL void duk_pop_2(duk_context *ctx); 581 | DUK_EXTERNAL_DECL void duk_pop_3(duk_context *ctx); 582 | 583 | /* 584 | * Type checks 585 | * 586 | * duk_is_none(), which would indicate whether index it outside of stack, 587 | * is not needed; duk_is_valid_index() gives the same information. 588 | */ 589 | 590 | DUK_EXTERNAL_DECL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index); 591 | DUK_EXTERNAL_DECL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type); 592 | DUK_EXTERNAL_DECL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index); 593 | DUK_EXTERNAL_DECL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask); 594 | 595 | DUK_EXTERNAL_DECL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index); 596 | DUK_EXTERNAL_DECL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index); 597 | DUK_EXTERNAL_DECL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index); 598 | DUK_EXTERNAL_DECL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index); 599 | DUK_EXTERNAL_DECL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index); 600 | DUK_EXTERNAL_DECL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index); 601 | DUK_EXTERNAL_DECL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index); 602 | DUK_EXTERNAL_DECL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index); 603 | DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index); 604 | DUK_EXTERNAL_DECL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index); 605 | DUK_EXTERNAL_DECL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index); 606 | 607 | DUK_EXTERNAL_DECL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index); 608 | DUK_EXTERNAL_DECL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index); 609 | DUK_EXTERNAL_DECL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index); 610 | DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index); 611 | DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index); 612 | DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index); 613 | 614 | DUK_EXTERNAL_DECL duk_bool_t duk_is_callable(duk_context *ctx, duk_idx_t index); 615 | DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index); 616 | DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index); 617 | DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index); 618 | 619 | #define duk_is_primitive(ctx,index) \ 620 | duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_UNDEFINED | \ 621 | DUK_TYPE_MASK_NULL | \ 622 | DUK_TYPE_MASK_BOOLEAN | \ 623 | DUK_TYPE_MASK_NUMBER | \ 624 | DUK_TYPE_MASK_STRING | \ 625 | DUK_TYPE_MASK_BUFFER | \ 626 | DUK_TYPE_MASK_POINTER | \ 627 | DUK_TYPE_MASK_LIGHTFUNC) 628 | 629 | #define duk_is_object_coercible(ctx,index) \ 630 | duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_BOOLEAN | \ 631 | DUK_TYPE_MASK_NUMBER | \ 632 | DUK_TYPE_MASK_STRING | \ 633 | DUK_TYPE_MASK_OBJECT | \ 634 | DUK_TYPE_MASK_BUFFER | \ 635 | DUK_TYPE_MASK_POINTER | \ 636 | DUK_TYPE_MASK_LIGHTFUNC) 637 | 638 | DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index); 639 | #define duk_is_error(ctx,index) \ 640 | (duk_get_error_code((ctx), (index)) != 0) 641 | 642 | /* 643 | * Get operations: no coercion, returns default value for invalid 644 | * indices and invalid value types. 645 | * 646 | * duk_get_undefined() and duk_get_null() would be pointless and 647 | * are not included. 648 | */ 649 | 650 | DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index); 651 | DUK_EXTERNAL_DECL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index); 652 | DUK_EXTERNAL_DECL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index); 653 | DUK_EXTERNAL_DECL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index); 654 | DUK_EXTERNAL_DECL const char *duk_get_string(duk_context *ctx, duk_idx_t index); 655 | DUK_EXTERNAL_DECL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len); 656 | DUK_EXTERNAL_DECL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 657 | DUK_EXTERNAL_DECL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 658 | DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t index); 659 | DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index); 660 | DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index); 661 | DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index); 662 | DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index); 663 | 664 | /* 665 | * Require operations: no coercion, throw error if index or type 666 | * is incorrect. No defaulting. 667 | */ 668 | 669 | #define duk_require_type_mask(ctx,index,mask) \ 670 | ((void) duk_check_type_mask((ctx), (index), (mask) | DUK_TYPE_MASK_THROW)) 671 | 672 | DUK_EXTERNAL_DECL void duk_require_undefined(duk_context *ctx, duk_idx_t index); 673 | DUK_EXTERNAL_DECL void duk_require_null(duk_context *ctx, duk_idx_t index); 674 | DUK_EXTERNAL_DECL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index); 675 | DUK_EXTERNAL_DECL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index); 676 | DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index); 677 | DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index); 678 | DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t index); 679 | DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len); 680 | DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 681 | DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 682 | DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t index); 683 | DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index); 684 | DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index); 685 | DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index); 686 | 687 | #define duk_require_object_coercible(ctx,index) \ 688 | ((void) duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_BOOLEAN | \ 689 | DUK_TYPE_MASK_NUMBER | \ 690 | DUK_TYPE_MASK_STRING | \ 691 | DUK_TYPE_MASK_OBJECT | \ 692 | DUK_TYPE_MASK_BUFFER | \ 693 | DUK_TYPE_MASK_POINTER | \ 694 | DUK_TYPE_MASK_LIGHTFUNC | \ 695 | DUK_TYPE_MASK_THROW)) 696 | 697 | /* 698 | * Coercion operations: in-place coercion, return coerced value where 699 | * applicable. If index is invalid, throw error. Some coercions may 700 | * throw an expected error (e.g. from a toString() or valueOf() call) 701 | * or an internal error (e.g. from out of memory). 702 | */ 703 | 704 | DUK_EXTERNAL_DECL void duk_to_undefined(duk_context *ctx, duk_idx_t index); 705 | DUK_EXTERNAL_DECL void duk_to_null(duk_context *ctx, duk_idx_t index); 706 | DUK_EXTERNAL_DECL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index); 707 | DUK_EXTERNAL_DECL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index); 708 | DUK_EXTERNAL_DECL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index); 709 | DUK_EXTERNAL_DECL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index); 710 | DUK_EXTERNAL_DECL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index); 711 | DUK_EXTERNAL_DECL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index); 712 | DUK_EXTERNAL_DECL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index); 713 | DUK_EXTERNAL_DECL const char *duk_to_string(duk_context *ctx, duk_idx_t index); 714 | DUK_EXTERNAL_DECL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len); 715 | DUK_EXTERNAL_DECL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t flags); 716 | DUK_EXTERNAL_DECL void *duk_to_pointer(duk_context *ctx, duk_idx_t index); 717 | DUK_EXTERNAL_DECL void duk_to_object(duk_context *ctx, duk_idx_t index); 718 | DUK_EXTERNAL_DECL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint); 719 | DUK_EXTERNAL_DECL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint); 720 | 721 | #define DUK_BUF_MODE_FIXED 0 /* internal: request fixed buffer result */ 722 | #define DUK_BUF_MODE_DYNAMIC 1 /* internal: request dynamic buffer result */ 723 | #define DUK_BUF_MODE_DONTCARE 2 /* internal: don't care about fixed/dynamic nature */ 724 | 725 | #define duk_to_buffer(ctx,index,out_size) \ 726 | duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_DONTCARE) 727 | #define duk_to_fixed_buffer(ctx,index,out_size) \ 728 | duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_FIXED) 729 | #define duk_to_dynamic_buffer(ctx,index,out_size) \ 730 | duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_DYNAMIC) 731 | 732 | /* safe variants of a few coercion operations */ 733 | DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len); 734 | #define duk_safe_to_string(ctx,index) \ 735 | duk_safe_to_lstring((ctx), (index), NULL) 736 | 737 | /* 738 | * Misc conversion 739 | */ 740 | 741 | DUK_EXTERNAL_DECL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index); 742 | DUK_EXTERNAL_DECL void duk_base64_decode(duk_context *ctx, duk_idx_t index); 743 | DUK_EXTERNAL_DECL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index); 744 | DUK_EXTERNAL_DECL void duk_hex_decode(duk_context *ctx, duk_idx_t index); 745 | DUK_EXTERNAL_DECL const char *duk_json_encode(duk_context *ctx, duk_idx_t index); 746 | DUK_EXTERNAL_DECL void duk_json_decode(duk_context *ctx, duk_idx_t index); 747 | 748 | /* 749 | * Buffer 750 | */ 751 | 752 | DUK_EXTERNAL_DECL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size); 753 | DUK_EXTERNAL_DECL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size); 754 | DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len); 755 | 756 | /* 757 | * Property access 758 | * 759 | * The basic function assumes key is on stack. The _string variant takes 760 | * a C string as a property name, while the _index variant takes an array 761 | * index as a property name (e.g. 123 is equivalent to the key "123"). 762 | */ 763 | 764 | DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index); 765 | DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key); 766 | DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); 767 | DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index); 768 | DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key); 769 | DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); 770 | DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index); 771 | DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key); 772 | DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); 773 | DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index); 774 | DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key); 775 | DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index); 776 | DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags); 777 | 778 | DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key); 779 | DUK_EXTERNAL_DECL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key); 780 | 781 | /* 782 | * Object prototype 783 | */ 784 | 785 | DUK_EXTERNAL_DECL void duk_get_prototype(duk_context *ctx, duk_idx_t index); 786 | DUK_EXTERNAL_DECL void duk_set_prototype(duk_context *ctx, duk_idx_t index); 787 | 788 | /* 789 | * Object finalizer 790 | */ 791 | 792 | DUK_EXTERNAL_DECL void duk_get_finalizer(duk_context *ctx, duk_idx_t index); 793 | DUK_EXTERNAL_DECL void duk_set_finalizer(duk_context *ctx, duk_idx_t index); 794 | 795 | /* 796 | * Global object 797 | */ 798 | 799 | DUK_EXTERNAL_DECL void duk_set_global_object(duk_context *ctx); 800 | 801 | /* 802 | * Duktape/C function magic value 803 | */ 804 | 805 | DUK_EXTERNAL_DECL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index); 806 | DUK_EXTERNAL_DECL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic); 807 | DUK_EXTERNAL_DECL duk_int_t duk_get_current_magic(duk_context *ctx); 808 | 809 | /* 810 | * Module helpers: put multiple function or constant properties 811 | */ 812 | 813 | DUK_EXTERNAL_DECL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs); 814 | DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers); 815 | 816 | /* 817 | * Variable access 818 | */ 819 | 820 | /* XXX: These calls are incomplete and not usable now. They are not (yet) 821 | * part of the public API. 822 | */ 823 | DUK_EXTERNAL_DECL void duk_get_var(duk_context *ctx); 824 | DUK_EXTERNAL_DECL void duk_put_var(duk_context *ctx); 825 | DUK_EXTERNAL_DECL duk_bool_t duk_del_var(duk_context *ctx); 826 | DUK_EXTERNAL_DECL duk_bool_t duk_has_var(duk_context *ctx); 827 | 828 | /* 829 | * Object operations 830 | */ 831 | 832 | DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_index); 833 | DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags); 834 | DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value); 835 | 836 | /* 837 | * String manipulation 838 | */ 839 | 840 | DUK_EXTERNAL_DECL void duk_concat(duk_context *ctx, duk_idx_t count); 841 | DUK_EXTERNAL_DECL void duk_join(duk_context *ctx, duk_idx_t count); 842 | DUK_EXTERNAL_DECL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata); 843 | DUK_EXTERNAL_DECL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata); 844 | DUK_EXTERNAL_DECL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_char_offset, duk_size_t end_char_offset); 845 | DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t index); 846 | DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset); 847 | 848 | /* 849 | * Ecmascript operators 850 | */ 851 | 852 | DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2); 853 | DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2); 854 | DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2); 855 | 856 | /* 857 | * Function (method) calls 858 | */ 859 | 860 | DUK_EXTERNAL_DECL void duk_call(duk_context *ctx, duk_idx_t nargs); 861 | DUK_EXTERNAL_DECL void duk_call_method(duk_context *ctx, duk_idx_t nargs); 862 | DUK_EXTERNAL_DECL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs); 863 | DUK_EXTERNAL_DECL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs); 864 | DUK_EXTERNAL_DECL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs); 865 | DUK_EXTERNAL_DECL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs); 866 | DUK_EXTERNAL_DECL void duk_new(duk_context *ctx, duk_idx_t nargs); 867 | DUK_EXTERNAL_DECL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs); 868 | DUK_EXTERNAL_DECL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets); 869 | 870 | /* 871 | * Thread management 872 | */ 873 | 874 | /* There are currently no native functions to yield/resume, due to the internal 875 | * limitations on coroutine handling. These will be added later. 876 | */ 877 | 878 | /* 879 | * Compilation and evaluation 880 | */ 881 | 882 | DUK_EXTERNAL_DECL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); 883 | DUK_EXTERNAL_DECL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags); 884 | 885 | /* plain */ 886 | #define duk_eval(ctx) \ 887 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 888 | (void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL)) 889 | 890 | #define duk_eval_noresult(ctx) \ 891 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 892 | (void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT)) 893 | 894 | #define duk_peval(ctx) \ 895 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 896 | duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE)) 897 | 898 | #define duk_peval_noresult(ctx) \ 899 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 900 | duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT)) 901 | 902 | #define duk_compile(ctx,flags) \ 903 | ((void) duk_compile_raw((ctx), NULL, 0, (flags))) 904 | 905 | #define duk_pcompile(ctx,flags) \ 906 | (duk_compile_raw((ctx), NULL, 0, (flags) | DUK_COMPILE_SAFE)) 907 | 908 | /* string */ 909 | #define duk_eval_string(ctx,src) \ 910 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 911 | (void) duk_eval_raw((ctx), (src), 0, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 912 | 913 | #define duk_eval_string_noresult(ctx,src) \ 914 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 915 | (void) duk_eval_raw((ctx), (src), 0, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT)) 916 | 917 | #define duk_peval_string(ctx,src) \ 918 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 919 | duk_eval_raw((ctx), (src), 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 920 | 921 | #define duk_peval_string_noresult(ctx,src) \ 922 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 923 | duk_eval_raw((ctx), (src), 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT)) 924 | 925 | #define duk_compile_string(ctx,flags,src) \ 926 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 927 | (void) duk_compile_raw((ctx), (src), 0, (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 928 | 929 | #define duk_compile_string_filename(ctx,flags,src) \ 930 | ((void) duk_compile_raw((ctx), (src), 0, (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 931 | 932 | #define duk_pcompile_string(ctx,flags,src) \ 933 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 934 | duk_compile_raw((ctx), (src), 0, (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 935 | 936 | #define duk_pcompile_string_filename(ctx,flags,src) \ 937 | (duk_compile_raw((ctx), (src), 0, (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN)) 938 | 939 | /* lstring */ 940 | #define duk_eval_lstring(ctx,buf,len) \ 941 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 942 | (void) duk_eval_raw((ctx), buf, len, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE)) 943 | 944 | #define duk_eval_lstring_noresult(ctx,buf,len) \ 945 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 946 | (void) duk_eval_raw((ctx), buf, len, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT)) 947 | 948 | #define duk_peval_lstring(ctx,buf,len) \ 949 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 950 | duk_eval_raw((ctx), buf, len, DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_SAFE)) 951 | 952 | #define duk_peval_lstring_noresult(ctx,buf,len) \ 953 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 954 | duk_eval_raw((ctx), buf, len, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT)) 955 | 956 | #define duk_compile_lstring(ctx,flags,buf,len) \ 957 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 958 | (void) duk_compile_raw((ctx), buf, len, (flags) | DUK_COMPILE_NOSOURCE)) 959 | 960 | #define duk_compile_lstring_filename(ctx,flags,buf,len) \ 961 | ((void) duk_compile_raw((ctx), buf, len, (flags) | DUK_COMPILE_NOSOURCE)) 962 | 963 | #define duk_pcompile_lstring(ctx,flags,buf,len) \ 964 | ((void) duk_push_string((ctx), (const char *) (__FILE__)), \ 965 | duk_compile_raw((ctx), buf, len, (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE)) 966 | 967 | #define duk_pcompile_lstring_filename(ctx,flags,buf,len) \ 968 | (duk_compile_raw((ctx), buf, len, (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE)) 969 | 970 | /* file */ 971 | #define duk_eval_file(ctx,path) \ 972 | ((void) duk_push_string_file_raw((ctx), (path), 0), \ 973 | (void) duk_push_string((ctx), (path)), \ 974 | (void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL)) 975 | 976 | #define duk_eval_file_noresult(ctx,path) \ 977 | ((void) duk_push_string_file_raw((ctx), (path), 0), \ 978 | (void) duk_push_string((ctx), (path)), \ 979 | (void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT)) 980 | 981 | #define duk_peval_file(ctx,path) \ 982 | ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \ 983 | (void) duk_push_string((ctx), (path)), \ 984 | duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE)) 985 | 986 | #define duk_peval_file_noresult(ctx,path) \ 987 | ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \ 988 | (void) duk_push_string((ctx), (path)), \ 989 | duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT)) 990 | 991 | #define duk_compile_file(ctx,flags,path) \ 992 | ((void) duk_push_string_file_raw((ctx), (path), 0), \ 993 | (void) duk_push_string((ctx), (path)), \ 994 | (void) duk_compile_raw((ctx), NULL, 0, (flags))) 995 | 996 | #define duk_pcompile_file(ctx,flags,path) \ 997 | ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \ 998 | (void) duk_push_string((ctx), (path)), \ 999 | duk_compile_raw((ctx), NULL, 0, (flags) | DUK_COMPILE_SAFE)) 1000 | 1001 | /* 1002 | * Bytecode load/dump 1003 | */ 1004 | 1005 | DUK_EXTERNAL_DECL void duk_dump_function(duk_context *ctx); 1006 | DUK_EXTERNAL_DECL void duk_load_function(duk_context *ctx); 1007 | 1008 | /* 1009 | * Logging 1010 | */ 1011 | 1012 | DUK_EXTERNAL_DECL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...); 1013 | DUK_EXTERNAL_DECL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap); 1014 | 1015 | /* 1016 | * Debugging 1017 | */ 1018 | 1019 | DUK_EXTERNAL_DECL void duk_push_context_dump(duk_context *ctx); 1020 | 1021 | #if defined(DUK_USE_FILE_IO) 1022 | /* internal use */ 1023 | #define duk_dump_context_filehandle(ctx,fh) \ 1024 | (duk_push_context_dump((ctx)), \ 1025 | DUK_FPRINTF((fh), "%s\n", duk_safe_to_string(ctx, -1)), \ 1026 | duk_pop(ctx)) 1027 | 1028 | /* external use */ 1029 | #define duk_dump_context_stdout(ctx) \ 1030 | duk_dump_context_filehandle((ctx), DUK_STDOUT) 1031 | #define duk_dump_context_stderr(ctx) \ 1032 | duk_dump_context_filehandle((ctx), DUK_STDERR) 1033 | #else /* DUK_USE_FILE_IO */ 1034 | #define duk_dump_context_stdout(ctx) ((void) 0) 1035 | #define duk_dump_context_stderr(ctx) ((void) 0) 1036 | #endif /* DUK_USE_FILE_IO */ 1037 | 1038 | /* 1039 | * Debugger (debug protocol) 1040 | */ 1041 | 1042 | DUK_EXTERNAL_DECL void duk_debugger_attach(duk_context *ctx, 1043 | duk_debug_read_function read_cb, 1044 | duk_debug_write_function write_cb, 1045 | duk_debug_peek_function peek_cb, 1046 | duk_debug_read_flush_function read_flush_cb, 1047 | duk_debug_write_flush_function write_flush_cb, 1048 | duk_debug_detached_function detached_cb, 1049 | void *udata); 1050 | DUK_EXTERNAL_DECL void duk_debugger_detach(duk_context *ctx); 1051 | DUK_EXTERNAL_DECL void duk_debugger_cooperate(duk_context *ctx); 1052 | 1053 | /* 1054 | * Date provider related constants 1055 | * 1056 | * NOTE: These are "semi public" - you should only use these if you write 1057 | * your own platform specific Date provider, see doc/datetime.rst. 1058 | */ 1059 | 1060 | /* Millisecond count constants. */ 1061 | #define DUK_DATE_MSEC_SECOND 1000L 1062 | #define DUK_DATE_MSEC_MINUTE (60L * 1000L) 1063 | #define DUK_DATE_MSEC_HOUR (60L * 60L * 1000L) 1064 | #define DUK_DATE_MSEC_DAY (24L * 60L * 60L * 1000L) 1065 | 1066 | /* Ecmascript date range is 100 million days from Epoch: 1067 | * > 100e6 * 24 * 60 * 60 * 1000 // 100M days in millisecs 1068 | * 8640000000000000 1069 | * (= 8.64e15) 1070 | */ 1071 | #define DUK_DATE_MSEC_100M_DAYS (8.64e15) 1072 | #define DUK_DATE_MSEC_100M_DAYS_LEEWAY (8.64e15 + 24 * 3600e3) 1073 | 1074 | /* Ecmascript year range: 1075 | * > new Date(100e6 * 24 * 3600e3).toISOString() 1076 | * '+275760-09-13T00:00:00.000Z' 1077 | * > new Date(-100e6 * 24 * 3600e3).toISOString() 1078 | * '-271821-04-20T00:00:00.000Z' 1079 | */ 1080 | #define DUK_DATE_MIN_ECMA_YEAR (-271821L) 1081 | #define DUK_DATE_MAX_ECMA_YEAR 275760L 1082 | 1083 | /* Part indices for internal breakdowns. Part order from DUK_DATE_IDX_YEAR 1084 | * to DUK_DATE_IDX_MILLISECOND matches argument ordering of Ecmascript API 1085 | * calls (like Date constructor call). Some functions in duk_bi_date.c 1086 | * depend on the specific ordering, so change with care. 16 bits are not 1087 | * enough for all parts (year, specifically). 1088 | * 1089 | * (Must be in-sync with genbuiltins.py.) 1090 | */ 1091 | #define DUK_DATE_IDX_YEAR 0 /* year */ 1092 | #define DUK_DATE_IDX_MONTH 1 /* month: 0 to 11 */ 1093 | #define DUK_DATE_IDX_DAY 2 /* day within month: 0 to 30 */ 1094 | #define DUK_DATE_IDX_HOUR 3 1095 | #define DUK_DATE_IDX_MINUTE 4 1096 | #define DUK_DATE_IDX_SECOND 5 1097 | #define DUK_DATE_IDX_MILLISECOND 6 1098 | #define DUK_DATE_IDX_WEEKDAY 7 /* weekday: 0 to 6, 0=sunday, 1=monday, etc */ 1099 | #define DUK_DATE_IDX_NUM_PARTS 8 1100 | 1101 | /* Internal API call flags, used for various functions in this file. 1102 | * Certain flags are used by only certain functions, but since the flags 1103 | * don't overlap, a single flags value can be passed around to multiple 1104 | * functions. 1105 | * 1106 | * The unused top bits of the flags field are also used to pass values 1107 | * to helpers (duk__get_part_helper() and duk__set_part_helper()). 1108 | * 1109 | * (Must be in-sync with genbuiltins.py.) 1110 | */ 1111 | 1112 | /* NOTE: when writing a Date provider you only need a few specific 1113 | * flags from here, the rest are internal. Avoid using anything you 1114 | * don't need. 1115 | */ 1116 | 1117 | #define DUK_DATE_FLAG_NAN_TO_ZERO (1 << 0) /* timeval breakdown: internal time value NaN -> zero */ 1118 | #define DUK_DATE_FLAG_NAN_TO_RANGE_ERROR (1 << 1) /* timeval breakdown: internal time value NaN -> RangeError (toISOString) */ 1119 | #define DUK_DATE_FLAG_ONEBASED (1 << 2) /* timeval breakdown: convert month and day-of-month parts to one-based (default is zero-based) */ 1120 | #define DUK_DATE_FLAG_EQUIVYEAR (1 << 3) /* timeval breakdown: replace year with equivalent year in the [1971,2037] range for DST calculations */ 1121 | #define DUK_DATE_FLAG_LOCALTIME (1 << 4) /* convert time value to local time */ 1122 | #define DUK_DATE_FLAG_SUB1900 (1 << 5) /* getter: subtract 1900 from year when getting year part */ 1123 | #define DUK_DATE_FLAG_TOSTRING_DATE (1 << 6) /* include date part in string conversion result */ 1124 | #define DUK_DATE_FLAG_TOSTRING_TIME (1 << 7) /* include time part in string conversion result */ 1125 | #define DUK_DATE_FLAG_TOSTRING_LOCALE (1 << 8) /* use locale specific formatting if available */ 1126 | #define DUK_DATE_FLAG_TIMESETTER (1 << 9) /* setter: call is a time setter (affects hour, min, sec, ms); otherwise date setter (affects year, month, day-in-month) */ 1127 | #define DUK_DATE_FLAG_YEAR_FIXUP (1 << 10) /* setter: perform 2-digit year fixup (00...99 -> 1900...1999) */ 1128 | #define DUK_DATE_FLAG_SEP_T (1 << 11) /* string conversion: use 'T' instead of ' ' as a separator */ 1129 | #define DUK_DATE_FLAG_VALUE_SHIFT 12 /* additional values begin at bit 12 */ 1130 | 1131 | /* 1132 | * C++ name mangling 1133 | */ 1134 | 1135 | #ifdef __cplusplus 1136 | /* end 'extern "C"' wrapper */ 1137 | } 1138 | #endif 1139 | 1140 | #endif /* DUK_API_PUBLIC_H_INCLUDED */ 1141 | 1142 | /* 1143 | * END PUBLIC API 1144 | */ 1145 | 1146 | /* 1147 | * Union to access IEEE double memory representation, indexes for double 1148 | * memory representation, and some macros for double manipulation. 1149 | * 1150 | * Also used by packed duk_tval. Use a union for bit manipulation to 1151 | * minimize aliasing issues in practice. The C99 standard does not 1152 | * guarantee that this should work, but it's a very widely supported 1153 | * practice for low level manipulation. 1154 | * 1155 | * IEEE double format summary: 1156 | * 1157 | * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 1158 | * A B C D E F G H 1159 | * 1160 | * s sign bit 1161 | * eee... exponent field 1162 | * fff... fraction 1163 | * 1164 | * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format. 1165 | * 1166 | * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a 1167 | * signaling NaN when the highest bit of the mantissa is zero, and a quiet 1168 | * NaN when the highest bit is set. 1169 | * 1170 | * At least three memory layouts are relevant here: 1171 | * 1172 | * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE 1173 | * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE 1174 | * D C B A H G F E Mixed/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME 1175 | * 1176 | * ARM is a special case: ARM double values are in mixed/cross endian 1177 | * format while ARM duk_uint64_t values are in standard little endian 1178 | * format (H G F E D C B A). When a double is read as a duk_uint64_t 1179 | * from memory, the register will contain the (logical) value 1180 | * E F G H A B C D. This requires some special handling below. 1181 | * 1182 | * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to 1183 | * the logical (big endian) order: 1184 | * 1185 | * byte order duk_uint8_t duk_uint16_t duk_uint32_t 1186 | * BE 01234567 0123 01 1187 | * LE 76543210 3210 10 1188 | * ME (ARM) 32107654 1032 01 1189 | * 1190 | * Some processors may alter NaN values in a floating point load+store. 1191 | * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a 1192 | * quiet one. This is catastrophic when NaN space is used in packed 1193 | * duk_tval values. See: misc/clang_aliasing.c. 1194 | */ 1195 | 1196 | #ifndef DUK_DBLUNION_H_INCLUDED 1197 | #define DUK_DBLUNION_H_INCLUDED 1198 | 1199 | /* 1200 | * Union for accessing double parts, also serves as packed duk_tval 1201 | */ 1202 | 1203 | union duk_double_union { 1204 | double d; 1205 | float f[2]; 1206 | #ifdef DUK_USE_64BIT_OPS 1207 | duk_uint64_t ull[1]; 1208 | #endif 1209 | duk_uint32_t ui[2]; 1210 | duk_uint16_t us[4]; 1211 | duk_uint8_t uc[8]; 1212 | #ifdef DUK_USE_PACKED_TVAL_POSSIBLE 1213 | void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */ 1214 | #endif 1215 | }; 1216 | 1217 | typedef union duk_double_union duk_double_union; 1218 | 1219 | /* 1220 | * Indexes of various types with respect to big endian (logical) layout 1221 | */ 1222 | 1223 | #if defined(DUK_USE_DOUBLE_LE) 1224 | #ifdef DUK_USE_64BIT_OPS 1225 | #define DUK_DBL_IDX_ULL0 0 1226 | #endif 1227 | #define DUK_DBL_IDX_UI0 1 1228 | #define DUK_DBL_IDX_UI1 0 1229 | #define DUK_DBL_IDX_US0 3 1230 | #define DUK_DBL_IDX_US1 2 1231 | #define DUK_DBL_IDX_US2 1 1232 | #define DUK_DBL_IDX_US3 0 1233 | #define DUK_DBL_IDX_UC0 7 1234 | #define DUK_DBL_IDX_UC1 6 1235 | #define DUK_DBL_IDX_UC2 5 1236 | #define DUK_DBL_IDX_UC3 4 1237 | #define DUK_DBL_IDX_UC4 3 1238 | #define DUK_DBL_IDX_UC5 2 1239 | #define DUK_DBL_IDX_UC6 1 1240 | #define DUK_DBL_IDX_UC7 0 1241 | #define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ 1242 | #define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ 1243 | #elif defined(DUK_USE_DOUBLE_BE) 1244 | #ifdef DUK_USE_64BIT_OPS 1245 | #define DUK_DBL_IDX_ULL0 0 1246 | #endif 1247 | #define DUK_DBL_IDX_UI0 0 1248 | #define DUK_DBL_IDX_UI1 1 1249 | #define DUK_DBL_IDX_US0 0 1250 | #define DUK_DBL_IDX_US1 1 1251 | #define DUK_DBL_IDX_US2 2 1252 | #define DUK_DBL_IDX_US3 3 1253 | #define DUK_DBL_IDX_UC0 0 1254 | #define DUK_DBL_IDX_UC1 1 1255 | #define DUK_DBL_IDX_UC2 2 1256 | #define DUK_DBL_IDX_UC3 3 1257 | #define DUK_DBL_IDX_UC4 4 1258 | #define DUK_DBL_IDX_UC5 5 1259 | #define DUK_DBL_IDX_UC6 6 1260 | #define DUK_DBL_IDX_UC7 7 1261 | #define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ 1262 | #define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ 1263 | #elif defined(DUK_USE_DOUBLE_ME) 1264 | #ifdef DUK_USE_64BIT_OPS 1265 | #define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */ 1266 | #endif 1267 | #define DUK_DBL_IDX_UI0 0 1268 | #define DUK_DBL_IDX_UI1 1 1269 | #define DUK_DBL_IDX_US0 1 1270 | #define DUK_DBL_IDX_US1 0 1271 | #define DUK_DBL_IDX_US2 3 1272 | #define DUK_DBL_IDX_US3 2 1273 | #define DUK_DBL_IDX_UC0 3 1274 | #define DUK_DBL_IDX_UC1 2 1275 | #define DUK_DBL_IDX_UC2 1 1276 | #define DUK_DBL_IDX_UC3 0 1277 | #define DUK_DBL_IDX_UC4 7 1278 | #define DUK_DBL_IDX_UC5 6 1279 | #define DUK_DBL_IDX_UC6 5 1280 | #define DUK_DBL_IDX_UC7 4 1281 | #define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ 1282 | #define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ 1283 | #else 1284 | #error internal error 1285 | #endif 1286 | 1287 | /* 1288 | * Helper macros for reading/writing memory representation parts, used 1289 | * by duk_numconv.c and duk_tval.h. 1290 | */ 1291 | 1292 | #define DUK_DBLUNION_SET_DOUBLE(u,v) do { \ 1293 | (u)->d = (v); \ 1294 | } while (0) 1295 | 1296 | #define DUK_DBLUNION_SET_HIGH32(u,v) do { \ 1297 | (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \ 1298 | } while (0) 1299 | 1300 | #ifdef DUK_USE_64BIT_OPS 1301 | #ifdef DUK_USE_DOUBLE_ME 1302 | #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ 1303 | (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \ 1304 | } while (0) 1305 | #else 1306 | #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ 1307 | (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \ 1308 | } while (0) 1309 | #endif 1310 | #else /* DUK_USE_64BIT_OPS */ 1311 | #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ 1312 | (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \ 1313 | (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \ 1314 | } while (0) 1315 | #endif /* DUK_USE_64BIT_OPS */ 1316 | 1317 | #define DUK_DBLUNION_SET_LOW32(u,v) do { \ 1318 | (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \ 1319 | } while (0) 1320 | 1321 | #define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d) 1322 | #define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0]) 1323 | #define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1]) 1324 | 1325 | #ifdef DUK_USE_64BIT_OPS 1326 | #ifdef DUK_USE_DOUBLE_ME 1327 | #define DUK_DBLUNION_SET_UINT64(u,v) do { \ 1328 | (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \ 1329 | (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \ 1330 | } while (0) 1331 | #define DUK_DBLUNION_GET_UINT64(u) \ 1332 | ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \ 1333 | ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1])) 1334 | #else 1335 | #define DUK_DBLUNION_SET_UINT64(u,v) do { \ 1336 | (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \ 1337 | } while (0) 1338 | #define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0]) 1339 | #endif 1340 | #define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v)) 1341 | #define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u))) 1342 | #endif /* DUK_USE_64BIT_OPS */ 1343 | 1344 | /* 1345 | * Double NaN manipulation macros related to NaN normalization needed when 1346 | * using the packed duk_tval representation. NaN normalization is necessary 1347 | * to keep double values compatible with the duk_tval format. 1348 | * 1349 | * When packed duk_tval is used, the NaN space is used to store pointers 1350 | * and other tagged values in addition to NaNs. Actual NaNs are normalized 1351 | * to a specific format. The macros below are used by the implementation 1352 | * to check and normalize NaN values when they might be created. The macros 1353 | * are essentially NOPs when the non-packed duk_tval representation is used. 1354 | * 1355 | * A FULL check is exact and checks all bits. A NOTFULL check is used by 1356 | * the packed duk_tval and works correctly for all NaNs except those that 1357 | * begin with 0x7ff0. Since the 'normalized NaN' values used with packed 1358 | * duk_tval begin with 0x7ff8, the partial check is reliable when packed 1359 | * duk_tval is used. 1360 | * 1361 | * The ME variant below is specifically for ARM byte order, which has the 1362 | * feature that while doubles have a mixed byte order (32107654), unsigned 1363 | * long long values has a little endian byte order (76543210). When writing 1364 | * a logical double value through a ULL pointer, the 32-bit words need to be 1365 | * swapped; hence the #ifdefs below for ULL writes with DUK_USE_DOUBLE_ME. 1366 | * This is not full ARM support but suffices for some environments. 1367 | */ 1368 | 1369 | #ifdef DUK_USE_64BIT_OPS 1370 | #ifdef DUK_USE_DOUBLE_ME 1371 | #define DUK__DBLUNION_SET_NAN_FULL(u) do { \ 1372 | (u)->ull[DUK_DBL_IDX_ULL0] = 0x000000007ff80000ULL; \ 1373 | } while (0) 1374 | #else 1375 | #define DUK__DBLUNION_SET_NAN_FULL(u) do { \ 1376 | (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \ 1377 | } while (0) 1378 | #endif 1379 | #else /* DUK_USE_64BIT_OPS */ 1380 | #define DUK__DBLUNION_SET_NAN_FULL(u) do { \ 1381 | (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \ 1382 | (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \ 1383 | } while (0) 1384 | #endif /* DUK_USE_64BIT_OPS */ 1385 | 1386 | #define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \ 1387 | (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \ 1388 | } while (0) 1389 | 1390 | #ifdef DUK_USE_64BIT_OPS 1391 | #ifdef DUK_USE_DOUBLE_ME 1392 | #define DUK__DBLUNION_IS_NAN_FULL(u) \ 1393 | /* E == 0x7ff, F != 0 => NaN */ \ 1394 | ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \ 1395 | ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0)) 1396 | #else 1397 | #define DUK__DBLUNION_IS_NAN_FULL(u) \ 1398 | /* E == 0x7ff, F != 0 => NaN */ \ 1399 | ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \ 1400 | ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0)) 1401 | #endif 1402 | #else /* DUK_USE_64BIT_OPS */ 1403 | #define DUK__DBLUNION_IS_NAN_FULL(u) \ 1404 | /* E == 0x7ff, F != 0 => NaN */ \ 1405 | ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \ 1406 | (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \ 1407 | (u)->ui[DUK_DBL_IDX_UI1] != 0)) 1408 | #endif /* DUK_USE_64BIT_OPS */ 1409 | 1410 | #define DUK__DBLUNION_IS_NAN_NOTFULL(u) \ 1411 | /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \ 1412 | ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \ 1413 | (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL)) 1414 | 1415 | #ifdef DUK_USE_64BIT_OPS 1416 | #ifdef DUK_USE_DOUBLE_ME 1417 | #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ 1418 | ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL) 1419 | #else 1420 | #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ 1421 | ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL) 1422 | #endif 1423 | #else /* DUK_USE_64BIT_OPS */ 1424 | #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ 1425 | (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \ 1426 | ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) 1427 | #endif /* DUK_USE_64BIT_OPS */ 1428 | 1429 | #define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \ 1430 | /* E == 0x7ff, F == 8 => normalized NaN */ \ 1431 | ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL) 1432 | 1433 | #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \ 1434 | if (DUK__DBLUNION_IS_NAN_FULL((u))) { \ 1435 | DUK__DBLUNION_SET_NAN_FULL((u)); \ 1436 | } \ 1437 | } while (0) 1438 | 1439 | #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \ 1440 | if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \ 1441 | DUK__DBLUNION_SET_NAN_NOTFULL((u)); \ 1442 | } \ 1443 | } while (0) 1444 | 1445 | /* Concrete macros for NaN handling used by the implementation internals. 1446 | * Chosen so that they match the duk_tval representation: with a packed 1447 | * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval 1448 | * these are essentially NOPs. 1449 | */ 1450 | 1451 | #if defined(DUK_USE_PACKED_TVAL) 1452 | #if defined(DUK_USE_FULL_TVAL) 1453 | #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u)) 1454 | #define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) 1455 | #define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u)) 1456 | #define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d)) 1457 | #else 1458 | #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u)) 1459 | #define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u)) 1460 | #define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u)) 1461 | #define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d)) 1462 | #endif 1463 | #define DUK_DBLUNION_IS_NORMALIZED(u) \ 1464 | (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \ 1465 | DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */ 1466 | #else /* DUK_USE_PACKED_TVAL */ 1467 | #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */ 1468 | #define DUK_DBLUNION_IS_NAN(u) (DUK_ISNAN((u)->d)) 1469 | #define DUK_DBLUNION_IS_NORMALIZED_NAN(u) (DUK_ISNAN((u)->d)) 1470 | #define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */ 1471 | #define DUK_DBLUNION_SET_NAN(u) do { \ 1472 | /* in non-packed representation we don't care about which NaN is used */ \ 1473 | (u)->d = DUK_DOUBLE_NAN; \ 1474 | } while (0) 1475 | #endif /* DUK_USE_PACKED_TVAL */ 1476 | 1477 | /* XXX: native 64-bit byteswaps when available */ 1478 | 1479 | /* 64-bit byteswap, same operation independent of target endianness. */ 1480 | #define DUK_DBLUNION_BSWAP64(u) do { \ 1481 | duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ 1482 | duk__bswaptmp1 = (u)->ui[0]; \ 1483 | duk__bswaptmp2 = (u)->ui[1]; \ 1484 | duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ 1485 | duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ 1486 | (u)->ui[0] = duk__bswaptmp2; \ 1487 | (u)->ui[1] = duk__bswaptmp1; \ 1488 | } while (0) 1489 | 1490 | /* Byteswap an IEEE double in the duk_double_union from host to network 1491 | * order. For a big endian target this is a no-op. 1492 | */ 1493 | #if defined(DUK_USE_DOUBLE_LE) 1494 | #define DUK_DBLUNION_DOUBLE_HTON(u) do { \ 1495 | duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ 1496 | duk__bswaptmp1 = (u)->ui[0]; \ 1497 | duk__bswaptmp2 = (u)->ui[1]; \ 1498 | duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ 1499 | duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ 1500 | (u)->ui[0] = duk__bswaptmp2; \ 1501 | (u)->ui[1] = duk__bswaptmp1; \ 1502 | } while (0) 1503 | #elif defined(DUK_USE_DOUBLE_ME) 1504 | #define DUK_DBLUNION_DOUBLE_HTON(u) do { \ 1505 | duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ 1506 | duk__bswaptmp1 = (u)->ui[0]; \ 1507 | duk__bswaptmp2 = (u)->ui[1]; \ 1508 | duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ 1509 | duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ 1510 | (u)->ui[0] = duk__bswaptmp1; \ 1511 | (u)->ui[1] = duk__bswaptmp2; \ 1512 | } while (0) 1513 | #elif defined(DUK_USE_DOUBLE_BE) 1514 | #define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0) 1515 | #else 1516 | #error internal error, double endianness insane 1517 | #endif 1518 | 1519 | /* Reverse operation is the same. */ 1520 | #define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u)) 1521 | 1522 | #endif /* DUK_DBLUNION_H_INCLUDED */ 1523 | 1524 | #endif /* DUKTAPE_H_INCLUDED */ 1525 | --------------------------------------------------------------------------------